diff options
| author | Stefan Boberg <[email protected]> | 2025-10-25 17:50:55 +0200 |
|---|---|---|
| committer | Stefan Boberg <[email protected]> | 2025-10-25 17:50:55 +0200 |
| commit | 07b37b2cb487fb0cd3587a67c83121777b672dc2 (patch) | |
| tree | 7fc6d0d4dfce46eb581ce55d3fdb2efe15284382 | |
| parent | suppress MSVC 4668 (diff) | |
| download | zen-07b37b2cb487fb0cd3587a67c83121777b672dc2.tar.xz zen-07b37b2cb487fb0cd3587a67c83121777b672dc2.zip | |
in-tree: gsl-lite
50 files changed, 21005 insertions, 6 deletions
diff --git a/src/zencore/xmake.lua b/src/zencore/xmake.lua index db53c93cd..5dcb6ded4 100644 --- a/src/zencore/xmake.lua +++ b/src/zencore/xmake.lua @@ -35,6 +35,7 @@ target('zencore') add_deps("json11") add_deps("fmt") add_deps("ryml") + add_deps("gsl-lite") add_packages( "vcpkg::openssl" -- required for crypto @@ -42,7 +43,6 @@ target('zencore') add_packages( "vcpkg::eastl", - "vcpkg::gsl-lite", "lz4", "xxhash", {public=true} diff --git a/src/zenhttp/xmake.lua b/src/zenhttp/xmake.lua index d89345dac..0109aa2f8 100644 --- a/src/zenhttp/xmake.lua +++ b/src/zenhttp/xmake.lua @@ -8,11 +8,11 @@ target('zenhttp') add_files("servers/httpsys.cpp", {unity_ignored=true}) add_includedirs("include", {public=true}) add_deps("zencore", "zentelemetry", "transport-sdk", "asio", "cpr") + add_deps("gsl-lite") add_packages( "vcpkg::curl", -- required by cpr "vcpkg::openssl", -- required by curl "vcpkg::zlib", -- required by curl - "vcpkg::gsl-lite", "http_parser" ) add_options("httpsys") diff --git a/src/zennet/xmake.lua b/src/zennet/xmake.lua index b44878acc..b31c799cc 100644 --- a/src/zennet/xmake.lua +++ b/src/zennet/xmake.lua @@ -7,6 +7,4 @@ target('zennet') add_files("**.cpp") add_includedirs("include", {public=true}) add_deps("zencore", "zenutil", "asio") - add_packages( - "vcpkg::gsl-lite" - ) + add_deps("gsl-lite") diff --git a/thirdparty/gsl-lite/.editorconfig b/thirdparty/gsl-lite/.editorconfig new file mode 100644 index 000000000..d1169ef88 --- /dev/null +++ b/thirdparty/gsl-lite/.editorconfig @@ -0,0 +1,3 @@ +[*] +indent_style = space +indent_size = 4
\ No newline at end of file diff --git a/thirdparty/gsl-lite/.gitattributes b/thirdparty/gsl-lite/.gitattributes new file mode 100644 index 000000000..689b10950 --- /dev/null +++ b/thirdparty/gsl-lite/.gitattributes @@ -0,0 +1,2 @@ +# Auto detect text files and perform LF normalization +* text=auto diff --git a/thirdparty/gsl-lite/.gitignore b/thirdparty/gsl-lite/.gitignore new file mode 100644 index 000000000..b3b901f7c --- /dev/null +++ b/thirdparty/gsl-lite/.gitignore @@ -0,0 +1,3 @@ +out/ +build*/ +.vs/ diff --git a/thirdparty/gsl-lite/CHANGES.txt b/thirdparty/gsl-lite/CHANGES.txt new file mode 100644 index 000000000..917195d1e --- /dev/null +++ b/thirdparty/gsl-lite/CHANGES.txt @@ -0,0 +1,727 @@ +Changes in gsl-lite +=================== + +version 1.0.1 2025-05-19 + +Fixes: +- Add `span<>` constructor overloads for `span<>::iterator` arguments. + This improves backward compatibility, since our iterator used to be a pointer in v0.*, which made + `span{ otherSpan.begin(), 0 }` work because we have constructor overloads that accept pointers. +- Add missing alias templates for polyfills. + + +version 1.0.0 2025-05-19 + +Breaking changes: +- gsl-lite now lives in the single header file `<gsl-lite/gsl-lite.hpp>`, and all its symbols reside in namespace `gsl_lite`. + By default, gsl-lite no longer defines a namespace `gsl` or the unprefixed `Expects()` and `Ensures()` macros for + precondition and postcondition checking. + This change enables coexistence with Microsoft GSL or other GSL implementations. (#194) + To minimize the impact of the breaking changes, gsl-lite introduces an optional GSL compatibility mode controlled by the + new configuration switch `gsl_FEATURE_GSL_COMPATIBILITY_MODE`, which is is disabled by default and can be enabled by + defining `gsl_FEATURE_GSL_COMPATIBILITY_MODE=1`. This should not be used in public header files of libraries which use + gsl-lite because it precludes the use of Microsoft GSL in the same translation unit. + The legacy header file `<gsl/gsl-lite.hpp>` now forwards to `<gsl-lite/gsl-lite.hpp>` and implicitly enables the GSL + compatibility mode. When the legacy header is included, it emits a warning message which urges to either migrate to header + `<gsl-lite/gsl-lite.hpp>`, namespace `gsl_lite`, and the prefixed contract checking macros `gsl_Expects()` and + `gsl_Ensures()`, or to explicitly request GSL compatibility by defining `gsl_FEATURE_GSL_COMPATIBILITY_MODE=1`. + Please refer to the migration guide in the gsl-lite documentation for guidance on how to adapt your code. + +Other changes: +- `span<>` now implements static extents. This was achieved by adapting the `span<>` implementation from Microsoft GSL, + back-porting it to support C++98 and older compilers. (#153) +- gsl-lite v1 has different defaults for the numerous configuration options and switches: + - `gsl_FEATURE_STRING_SPAN`: + Version-1 default: `gsl_FEATURE_STRING_SPAN=0` + Version-0 default: `gsl_FEATURE_STRING_SPAN=1` + Reason: string spans are no longer part of the GSL specification. + - `gsl_FEATURE_BYTE`: + Version-1 default: `gsl_FEATURE_BYTE=0` + Version-0 default: `gsl_FEATURE_BYTE=1` + Reason: `byte` has been superseded by `std::byte` in C++17. + - `gsl_CONFIG_DEPRECATE_TO_LEVEL`: + Version-1 default: `gsl_CONFIG_DEPRECATE_TO_LEVEL=9` + Version-0 default: `gsl_CONFIG_DEPRECATE_TO_LEVEL=0` + - `gsl_CONFIG_INDEX_TYPE`: + Version-1 default: `std::ptrdiff_t`: + Version-0 default: `gsl_CONFIG_SPAN_INDEX_TYPE` (defaults to `std::size_t`) + Reason: the GSL specifies `gsl::index` to be a signed type. + - `gsl_CONFIG_ALLOWS_SPAN_COMPARISON`: + Version-1 default: `gsl_CONFIG_ALLOWS_SPAN_COMPARISON=0` + Version-0 default: `gsl_CONFIG_ALLOWS_SPAN_COMPARISON=1` + Reason: C++20 `std::span<>` does not support comparison because semantics (deep vs. shallow) are unclear. + - `gsl_CONFIG_NOT_NULL_EXPLICIT_CTOR`: + Version-1 default: `gsl_CONFIG_NOT_NULL_EXPLICIT_CTOR=1` + Version-0 default: `gsl_CONFIG_NOT_NULL_EXPLICIT_CTOR=0` + Reason: see https://github.com/Microsoft/GSL/issues/395. + (Note that `not_null<>` in Microsoft GSL has an implicit constructor, cf. https://github.com/Microsoft/GSL/issues/699).) + - `gsl_CONFIG_TRANSPARENT_NOT_NULL`: + Version-1 default: `gsl_CONFIG_TRANSPARENT_NOT_NULL=1` + Version-0 default: `gsl_CONFIG_TRANSPARENT_NOT_NULL=0` + Reason: enables conformant behavior for `not_null<>::get()`. + - `gsl_CONFIG_NARROW_THROWS_ON_TRUNCATION`: + Version-1 default: `gsl_CONFIG_NARROW_THROWS_ON_TRUNCATION=1` + Version-0 default: `gsl_CONFIG_NARROW_THROWS_ON_TRUNCATION=0` + Reason: enables conformant behavior for `narrow<>()` (cf. #52). + - default runtime contract violation handling: + Version-1 default: `gsl_CONFIG_CONTRACT_VIOLATION_ASSERTS` + Version-0 default: `gsl_CONFIG_CONTRACT_VIOLATION_TERMINATES` + Reason: the mode enabled by `gsl_CONFIG_CONTRACT_VIOLATION_ASSERTS` is consistent with the behavior of the `assert()` macro + while retaining runtime contract checks even if `NDEBUG` is defined. +- `narrow<>()` and `narrow_failfast<>()` now support non-totally-ordered types such as `std::complex<>`, borrowing from + https://github.com/microsoft/GSL/pull/986. (#309) + +- gsl-lite now emits a warning if a configuration option alters the binary interface, leading to possible ODR violations. + The warning can be explicitly overridden by defining `gsl_CONFIG_ACKNOWLEDGE_NONSTANDARD_ABI`. + +- For MSVC on Windows, gsl-lite now uses `#pragma detect_mismatch()` to diagnose ABI incompatibilities at link time. + + +Fixes: +- In C++98 mode, the faulty definition of the internal function macro `gsl_STATIC_ASSERT_()` was corrected, fixing an unwanted + predicate inversion for some internal compile-time checks. +- Contract check macros now always expand to an expression or a statement, which avoids compiler warnings. + + +Deprecations and removals: +- Deprecated unsafe `span<>` member function `as_span<>()`. +- Removed `Owner()` and `implicit` macros, which already were disabled by default. +- Removed `finally()`, `on_error()`, and `on_return()` implementation for C++98. +- Removed many deprecated functions: + - `as_writeable_bytes()` + - `basic_string_span<>` member function `operator()` for indexing + - `span<>` constructor overloads and `make_span()` overloads accepting reference arguments, `unique_ptr<>`, or `shared_ptr<>` arguments + - `span<>` member functions `at()` and `operator()` for indexing + - `span<>` member functions `length()`, `length_bytes()`, `as_bytes()`, `as_writeable_bytes()` +- Removed the non-templated functions `finally()`, `on_return()`, and `on_error()` for C++98. + + +version 0.43.0 2025-05-05 + +Additions: +- `not_null<>` now supports function pointers and nullable function objects such as `std::function<>` and (for C++11 and + newer) defines a conditionally enabled forwarding `operator()` to permit function-call syntax (#353, thanks to @n0F4x) +- `not_null<>` now supports implicit construction from non-nullable arguments such as function objects and functions (#353) +- Add `is_nullable<>` trait (#353, thanks to @BenFrantzDale) +- Add tentative C++26 detection macro `gsl_CPP26_OR_GREATER`, `CONSTEXPR_26` language feature, and `gsl_constexpr26` + keyword macro +- For C++20 and newer, define `operator<=>` for `not_null<>` in C++20 +- For C++20 and newer, Add `gsl_NO_UNIQUE_ADDRESS` which uses MSVC's ABI-breaking `[[msvc::no_unique_address]]` if + necessary + +Changes: +- Add feature macro `gsl_FEATURE_STRING_SPAN`, defaulting to 0 for version-1 defaults, to control the availability of + string spans, which are no longer part of the GSL specification and have been deprecated for a while +- Add feature macro `gsl_FEATURE_BYTE`, defaulting to 0 for version-1 defaults, to control the availability of `byte`, + which has been superseded by `std::byte` in C++17 +- If `gsl_FEATURE_STRING_SPAN=0`, we now avoid pulling in standard library header files `<ios>` and `<string>` +- In version-1 mode, default to `gsl_CONFIG_CONTRACT_VIOLATION_ASSERTS` rather than `gsl_CONFIG_CONTRACT_VIOLATION_TERMINATES`, + which is more convenient in practice +- `gsl_FEATURE_WITH_CONTAINER_TO_STD` now defaults to 0 with version-1 defaults (#353) +- Remove unsupported CUDA toolkits and older GCC versions no longer available through Azure Pipelines (#353) + +Fixes: +- Add `[[maybe_unused]]` annotations to macro-generated function definitions to avoid Clang warnings about unused functions + in anonymous namespaces + +version 0.42.0 2024-11-01 + +Additions: +- Define `gsl_MAYBE_UNUSED_MEMBER` for `[[maybe_unused]]` annotations on members + (https://github.com/gsl-lite/gsl-lite/commit/34ba5141492a88912e2055e08cd1bdd6714431c5) +- Support `not_null<void*>` (#341, thanks to @BenFrantzDale) +- Support `not_null<>` for `unique_ptr<void, D>` and `shared_ptr<void>` (#349, thanks to @BenFrantzDale) + +Changes: +- For modern (≥v1) defaults, `finally()`, `on_return()`, and `on_error()` are now implemented without virtual function calls (#342) +- Deprecate `finally()`, `on_return()`, and `on_error()` for pre-C++11 (#342) +- `narrow_failfast<>()` now uses `gsl_Assert()` rather than `gsl_Expects()` to express the contract check (#351) +- `std::hash<gsl_lite::byte>` now forwards to `std::hash<unsigned char>` (#343) +- Add Continuous Integration for GCC 13, Clang 17 to 19, and for NVCC 12.6; remove CI for GCC 10 on macOS and for + Apple Clang 12.0.5 and earlier (#351) + +Fixes: +- `std::terminate()` cannot be called from CUDA device code, but the call may go undetected due to a NVCC issue; + for `!gsl_CONFIG( NARROW_THROWS_ON_TRUNCATION )`, `narrow<>()` now makes sure that the program is terminated by + issuing a trap instruction if `std::terminate()` is not available (#351, thanks to @pauleonix for helping track this down) +- `narrow<>()` no longer responds to `gsl_CONFIG_CONTRACT_VIOLATION_THROWS` because it does not do contract checking; + therefore, it now plainly fails to compile if `gsl_CONFIG_NARROW_THROWS_ON_TRUNCATION` is set to 1 even though + exceptions are unavailable (e.g. in device code) (#351) +- Fix issues in test suite (#338, thanks to @musicinmybrain) + +version 0.41.0 2023-04-12 + +Additions: +- Add tentative C++23 detection macro `gsl_CPP23_OR_GREATER`, `CONSTEXPR_23` language feature, and `gsl_constexpr23` + keyword macro (#329) +- Add `gsl_CONFIG_VALIDATES_UNENFORCED_CONTRACT_EXPRESSIONS` config switch for suppressing the compile-time syntax + validation of contract check expressions (#330) + +Changes: +- Deprecate `string_span` and `zstring_span` and prepare for removal (#335) +- Continuous Integration now also tests GCC 12, Clang 14 thru 16, and NVCC 11.8 and 12.1 +- Remove Continuous Integration for GCC 6 and earlier, Clang 5 and earlier, Apple Clang 11.0.0 and earlier, and + CUDA 10.2 and earlier (#333, #334) + +Fixes: +- Use NVCC's `__builtin_assume()` for `gsl_ASSUME_()` in device code (#324, thanks to @codecircuit) +- Fix `not_null_ic<>` copy construction (#326, thanks to @runer112) +- Respect libc++ configuration option to disable `wchar_t` (#331, thanks to @burnpanck) +- Suppress "-Wweak-vtables" warning for Clang (#332, thanks to @mrahn) +- Suppress "-Wuseless-cast" warning for GCC (#332, thanks to @wirew0rm) + +version 0.40.0 2021-11-05 + +Additions: +- Add debug-mode contract checking macros `gsl_ExpectsDebug()`, `gsl_EnsuresDebug()`, `gsl_AssertDebug()` which are sensitive + to the `NDEBUG` macro, and thus similar to `assert()` (#316) +- Add dedicated contract check configuration macros for device code: `gsl_CONFIG_DEVICE_CONTRACT_CHECKING_AUDIT`/`ON`/`OFF`, + `gsl_CONFIG_DEVICE_CONTRACT_VIOLATION_ASSERTS`/`TRAPS`/`CALLS_HANDLER`, and + `gsl_CONFIG_DEVICE_UNENFORCED_CONTRACTS_ASSUME`/`ELIDE` (#317) +- Add `gsl::is_valid()` for explicitly detecting the moved-from state of a `gsl::not_null<>` object (#318) +- Add device code detection macro `gsl_DEVICE_CODE` (evaluates to 1 when compiling CUDA device code, 0 when compiling host code) + +Changes: +- Continuous Integration now also tests Clang 13 and updates CUDA version to 11.5 +- Improve documentation for contract checking macros and configuration macros + +Fixes: +- Check for `gsl::` target rather than nonexistent `gsl-lite::` target in Config.cmake (#315, thanks to @Ram-Z) + +version 0.39.0 2021-09-30 + +Additions: +- Add `gsl::make_unique<T>()` and `gsl::make_shared<T>()` which resemble the eponymous functions from `std` but return + `gsl::not_null<std::unique_ptr<T>>` and `gsl::not_null<std::shared_ptr<T>>` (#312) +- Add basic support for NVHPC compiler (#308, thanks to @olupton) + +Changes: +- Continuous Integration now also tests GCC 11, Clang 12, and AppleClang 12.0.5 and 13, and updates CUDA version to 11.4 (#314) +- Remove C++98 polyfills `std98::equal()`, `std98::lexicographical_compare()` from public interface (#313) + +Fixes: +- `gsl::not_null<std::shared_ptr<T>>` now correctly converts to `std::weak_ptr<T>` (#311, thanks to @stohrendorf) + +version 0.38.1 2021-04-22 + +Additions: +- Add feature detection macro `gsl_HAVE( C99_PREPROCESSOR )` +- Add `gsl_CONSTRAINT()` which can be used to impose concept requirements on template type parameters in a backward-compatible manner: + `template< gsl_CONSTRAINT(Concept) T >` expands to `template< Concept T >` for C++20 and to `template< typename T >` otherwise +- Add C++20 polyfill `std20::endian()` (#305) +- Restore Continuous Integration testing for NVCC 10.2 +- Add basic CUDA runtime tests to test suite (#307) + +Changes: +- Continuous Integration now also tests "RelWithDebInfo" configuration for select compilers and platforms + +Fixes: +- Fix regression in precondition/postcondition/assertion checks for CUDA (cf. #302, thanks to @Spielix) +- Add workaround for GCC bug to test suite (cf. #303, thanks to @sanjayankur31) +- Fix endianness issues in test suite (cf. #304, thanks to @sanjayankur31) +- Improve `constexpr` support for `span<>`; add `constexpr` tests (#306) + +version 0.38.0 2021-03-31 + +Additions: +- Add macros `gsl_Assert()`, `gsl_AssertAudit()` to express checks which are neither pre- nor postconditions (#294) +- Add fail-fast operation `gsl_FailFast()` which is guaranteed to terminate normal execution in some way + (exception, `std::terminate()`, or trap instruction) (#294) +- Add configuration option `gsl_CONFIG_CONTRACT_VIOLATION_TRAPS` which makes `gsl_Expects()`/`gsl_Ensures()`/`gsl_Assert()` (and + the `Audit` variants if audit mode is enabled) and `gsl_FailFast()` execute a trap instruction in case of a contract violation +- Add configuration option `gsl_CONFIG_CONTRACT_VIOLATION_ASSERTS` which implements `gsl_Expects()`/`gsl_Ensures()`/`gsl_Assert()` + (and the `Audit` variants if audit mode is enabled) in terms of the `assert()` macro from the standard library. This has the + benefits that both legacy assertions and contract checks can be globally suppressed with a single macro (`NDEBUG`), and that + `assert()` prints an informative error message which contains the contract check expression. +- Add `as_nullable()` function (#251, thanks to @petamas) +- Add compiler detection macro for NVCC (#294) +- Add compiler detection macro and tentative support (no CI) for ARMCC (#293; thanks to @woodsking2) +- Add conditional `std::hash<>` specialization for `not_null<>` (#297; thanks to @mbs-c) +- Track language and library versions separately; new macros `gsl_STDLIB_CPPxx_OR_GREATER` indicate availability of the standard library +- Add feature detection macros `gsl_HAVE( HASH )`, `gsl_HAVE( MOVE_FORWARD )`, `gsl_HAVE( OVERRIDE_FINAL )` +- Add `size_type` to `span<>` and `basic_string_span<>` +- Add Continuous Integration testing for NVCC 11.0-11.2 (CUDA14, CUDA17), Clang 10-11, GCC 10, Apple Clang 12.0.0 +- Add Continuous Integration testing for Clang with libstdc++ +- Add Valgrind "memcheck" run to Continuous Integration +- Add testing for more configuration scenarios, e.g. building with exceptions disabled and using different ways of precondition + violation handling + +Changes: +- Remove dependency on standard library headers <algorithm> and <iterator> (#290, #295; thanks to @mpusz) +- Use of `gsl_HAVE()`, `gsl_CONFIG()`, `gsl_FEATURE()` with unknown arguments now causes compilation errors (#272) +- `narrow<>()` now issues a `static_assert()` that refers to `narrow_failfast<>()` if exceptions are unavailable (#269) +- With version-1 defaults, `not_null<>` now has a specialization for raw pointers which avoids unnecessary contract checks (#300) +- The contract expression is now part of the exception message in `gsl_CONFIG_CONTRACT_VIOLATION_THROWS` mode +- `narrowing_error` now produces a less unhelpful exception message ("narrowing_error") +- `gsl_noexcept` now falls back to `throw()` if `noexcept` is unavailable +- Most symbols are now accessible through both `namespace gsl` and `namespace gsl_lite` to ease migration +- `not_null_ic<>` is now also visible in `namespace gsl_lite` (#280; thanks to @woodsking2) +- `nullptr_t` comparison operators for `not_null<>` are now explicitly deleted +- More uses of `gsl_NODISCARD` throughout the library +- For NVCC ≥11.3, make use of new `__builtin_unreachable()` intrinsic in `gsl_CONFIG_UNENFORCED_CONTRACTS_ASSUME` mode + +Fixes: +- Many bugfixes (#249, #250, #255, #256, #262, #263, #268, #270, #271, #286, #287, #292; thanks to @fodinabor, @KazDragon, + @martinmoene, @Maximus5, @Pesa, @petamas, @travnick) + +version 0.37.0 2020-05-13 + +Additions: +- Add configuration option `gsl_CONFIG_NARROW_THROWS_ON_TRUNCATION` +- Add configuration option `gsl_CONFIG_ALLOWS_SPAN_COMPARISON` +- Add `narrow_failfast<>()`, a fast-fail variant of `narrow<>()` (#52) +- Add `front()` and `back()` to `span<>` and `basic_string_span<>` (#241, thanks to @ned14) + +Changes: +- Rename `as_writeable_bytes()` -> `as_writable_bytes()` to follow C++20 in spelling; the old name is still provided for compatibility +- Rename `gsl_DEPRECATED()` -> `gsl_DEPRECATED_MSG()`, add `gsl_DEPRECATED` +- Add more `gsl_DEPRECATED()` annotations +- Deprecate `span<>::at()`, `basic_string_span<>::at()`, and call indexing +- Minor documentation improvements +- Unify internal SFINAE macros to `gsl_ENABLE_IF_()` (#238; thanks to @martinmoene) +- Add more comprehensive tests for `narrow<>()` and `narrow_failfast<>()` + +Fixes: +- Fix spurious static assertion for pre-/postcondition check arguments explicitly convertible to bool if `gsl_CONFIG_CONTRACT_CHECKING_OFF` is defined +- Fix hard failure in `span<>` constrained constructor (#242, thanks to @orangeturtle739) +- Make `gsl::detail::is_compatible_container<>` a proper type trait + + +version 0.36.0 2020-01-24 + +The repository now moved to a dedicated GitHub organization: https://github.com/gsl-lite/gsl-lite + +gsl-lite is now mostly maintained by @mbeutel (#175). + +Additions: +- Describe versioning semantics in Readme +- Add audit-level contract checks `gsl_ExpectsAudit()` and `gsl_EnsuresAudit()` (#172) +- Add `basic_zstring_span<>` and `zstring_span` (#136, #154, thanks to @chan-lee) +- Add support for user-defined contract violation handler `fail_fast_assert_handler()` +- Add macros `gsl_NORETURN`, `gsl_NODISCARD`, `gsl_DEPRECATED()`, `gsl_constexpr17`, `gsl_constexpr20` +- Add C++11 polyfills in `gsl::std11`: `remove_reference<>` +- Add C++17 polyfills in `gsl::std17`: `conjunction<>`, `disjunction<>`, `negation<>`, `void_t<>` +- Add C++20 polyfills in `gsl::std20`: `identity`, `type_identity<>`, `ssize()` (#144, #180), `remove_cvref<>` +- Add configuration macro `gsl_CONFIG_TRANSPARENT_NOT_NULL` (#185) +- Add configuration macro `gsl_CONFIG_INDEX_TYPE` which controls the type of `gsl::index` independently of `gsl::span<>::index_type` (#169) +- Add language feature macro `gsl_HAVE_EXCEPTIONS` +- Add macros `gsl_DEFINE_ENUM_BITMASK_OPERATORS()` and `gsl_DEFINE_ENUM_RELATIONAL_OPERATORS()` +- Add header <gsl-lite/gsl-lite.hpp> and namespace `gsl_lite` to pave the way for future coexistence with M-GSL (#221, #222) +- Add Continuous Integration for more versions of GCC (4.7 through 9), Clang (3.5 through 9), AppleClang (7.3 through 11), and MSVC (2010 through 2019) +- Run tests with AddressSanitizer and UndefinedBehaviorSanitizer in CI (GCC 9, Clang 9) +- Add Continuous Integration for NVCC 10.2 (with GCC 7, 8 on Linux, MSVC 2019 on Windows) to test CUDA support + +Changes: +- `not_null<>` now properly supports smart pointers (#184, #197, huge thanks to @petamas) +- Restructure contract checking configuration macros such that checking policy (off, on, audit), violation handling (throws, terminates, calls handler) and unenforced contract handling (assume, elide) can be configured independently (cf. https://github.com/martinmoene/gsl-lite/#contract-violation-response-macros) +- `gsl_noexcept` no longer depends on contract violation settings (cf. https://github.com/martinmoene/gsl-lite/commit/0c296a9c986ac070997610fc7cf86e9c517558bf) +- `gsl_FEATURE_IMPLICIT_MACRO` now defaults to 0 (#156, thanks to @tadeu) +- AppleClang is now considered a separate compiler (use `gsl_COMPILER_APPLECLANG_VERSION` for checking) +- CMake installs arch-independent by default +- CMake doesn't install M-GSL compatibility headers by default +- gsl-lite now compiles warning-free with MSVC at warning level 4 +- Many small improvements (thanks to @AraHaan, @codecircuit, @elnull, @ilyalesokhin-starkware, @ngrodzitski, @petamas, @stohrendorf, @theodelrieu) + + +version 0.34.0 2019-03-21 + +Additions: +- Add macro gsl_REQUIRES_T() (nonstd lite issue 18) + +Changes +- Change the CMake package folder name to gsl-lite (it was gsl) +- Add a usage description for the Conda package manager to the Readme. +- Update lest test framework to v1.35.1. + + +version 0.33.0 2019-03-08 + +Additions: +- Add script/create-cov-rpt.py to create OpenCppCoverage report (nonstd-lite project issue 29) +- Add script/create-vcpkg.py (nonstd-lite-project issue 28) +- Add script/upload-conan.py (nonstd-lite-project issue 26) +- Add conanfile.py, edit it from script/update-version.py (nonstd-lite-project issue 26) +- Add CMake installation and config-file packaging; Let tests and example use gsl-lite interface library +- Add "LANGUAGES CXX" to CMake project +- Add GNUC -Wsign-conversion warning to CMake configuration +- Add AppleClang to CMake configuration +- Add OSX to Travis configuration +- Add TOC entry for Standard selection macro (#128, thanks to @egarrulo) +- Add span::ssize(), ssize(span), size(span) (#144) +- Add test/tc-cl.bat + +Changes: +- Rename "Guideline support library" to "Guidelines -" (#134) +- Align Appveyor configuration (plan 9, nonstd-lite-project issue 14) +- Align CMakefiles.txt (plan 8, nonstd-lite-project issue 13) +- Align test scripts (nonstd-lite-project issue 12) +- Align badges in readme (nonstd-lite-project issue 3) +- Obviate need for -DNOMINMAX with MSVC (nonstd-lite issue 16) +- Prevent and suppress warnings from clang +- Let ctest produce output on failure +- Update lest test framework to v1.35.0. + +Fixes: +- Fix CMake install command (expected-lite issue 25, thanks to @rmorozov) +- Fix clashing CMake cached variable, use 'gsl' for namespace and package folder (thanks to @rmorozov) +- Fix template argument in not_null<> comparison operators (#143, thanks @stohrendorf) +- Fix macro gsl_IN_STD (#142, thanks to @Flamefire) +- Fix possible int overflow in nonstd::span::subspan() range (issue #138, thanks to @fefe17) +- Fix link to P0122 (#130, thanks to @alexeyr) +- Fix for misleading __cplusplus of GCC 4.7.0 and earlier (#127, thanks to @egarrulo) +- Fix final_action_return() and final_action_error() during stack unwinding (#126, thanks to @patstew) +- Fix unused parameter if Expects elided via new macro gsl_EXPECTS_UNUSED_PARAM (#123, #124, thanks to @kugelrund) + +version 0.32.0 2018-05-12 + +- Review not_null (issue #122). +- Add not_null_ic with implicit constructor, allowing copy-initialization. +- Enable making not_null constructor explicit via gsl_CONFIG_NOT_NULL_EXPLICIT_CTOR, default 0 (breaking, issue #46). +- Enable not_null get() return by const & via gsl_CONFIG_NOT_NULL_GET_BY_CONST_REF (via M-GSL PR 651 @xaxxon, PR 675 @ericLemanissier). +- Change constraint on not_null construction from is_convertible to is_constructible (via M-GSL PR 650, @xaxxon). +- Change to take not_null constructor argument by const & when rvalue references are not available. +- Add not_null non-is-default rvalue reference copy-constructor, copy-assignment. +- Remove not_null converting assignment operator. +- Rename to gsl_HAVE_EXPLICIT. +- Adapt several compile-time tests for not_null with explicit constructor. +- Fix GNUC C++98 compilation by making RefCounted conversion function const in not_null.t.cpp. + +version 0.31.0 2018-05-10 + +- Change span towards proposal p0122r7 (issue #118). +- Add gsl_lite_MAJOR, gsl_lite_MINOR, gsl_lite_PATCH, script/update-version.py. +- Add configuration selector gsl_CONFIG_DEPRECATE_TO_LEVEL. +- Add feature selector gsl_FEATURE_WITH_CONTAINER_TO_STD. +- Add feature selector gsl_FEATURE_MAKE_SPAN_TO_STD. +- Add feature selector gsl_FEATURE_BYTE_SPAN_TO_STD. +- Add macros gsl_FEATURE(), gsl_CONFIG(), gsl_HAVE(). +- Add macro gsl_ADDRESSOF(x). +- Add span::value_type. +- Add details::can_construct_span_from<>. +- Add convertible constraint to span C-array constructor. +- Add class template argument deduction guides for span. +- Add make_span( with_container_t, ...) creator functions. +- Add byte_span() creator functions. +- Use C++11 constexpr where possible. +- Parenthesize macro arguments. +- Omit macros min(), max() via -DNOMINMAX. +- Update t-all.bat for various configuration and feature selections. + +version 0.30.0 2018-05-06 + +- Add support for DJGPP cross compiler is introduced (PR #107, thanks to Tom� Zeman, @zemasoft). +- Add Readme.md to example/cmake-pkg. +- Update lest test framework to v1.33.1. +- Allow strict aliasing with Clang and GNUC for gsl::byte (issue #114). +- Enable differentiating between MSVC 14.0 (VS 2015) and 14.1 (VS 2017), also report clang version. +- Remove the space after ':' in FILE: LINE in reported locations (issue #112). +- Avoid MSVC level 4 warning C4127: conditional expression is constant (issue #115, thanks to @kpeace) +- Add a constructor to allow rvalue to const lvalue conversion (issue #113, PR #117, thanks to @theodelrieu ) +- Enable owner alias template for VC12 (Issue #111, thanks to @sg-james) +- Fix omission of #include <algorithm> +- Fix clang compilation by specifying C++ standard +- Fix gsl-lite version in section "As CMake package" +- Fix type in a test of span has been correced (PR #105, thanks to Tom� Zeman, @zemasoft) + +version 0.29.0 2018-03-03 + +- Added CMake package, thanks to @FlorianWolters (PR #100, #103). +- Added CMake option GSL_LITE_OPT_BUILD_TESTS to ./CMakeLists.txt (default off). +- Added CMake option GSL_LITE_OPT_BUILD_EXAMPLESto ./CMakeLists.txt (default off). +- Added scipt/install-gsl-pkg.py +- Added script use-gsl-pkg.py as part of an example that uses the package. +- Added script/update-version.py to updated gsl-lite's version number in relevant files. +- Added type `gsl::index` for container indices, subscripts and sizes. +- Fixed padding of the output stream operator of class `string_span` to pad to the right side. +- Deprecated span::length() and span::length_bytes() (issue #99). +- Deprecated constructors span(shared_ptr<element_type> const & ptr) and span(unique_ptr<element_type> const & ptr)` (issue #98). +- Added documentation section 'Deprecation'. +- Expanded documentation section 'Installation and use'. +- Updated documentation section 'Reported to work with'. + +version 0.28.0 2018-01-01 + +- Expand Travis and Appveyor CI compiler matrices and use CMake configuration. +- Fix to use CMAKE_CXX_COMPILER_VERSION in CMake configuration. +- Add targets for various -std flags for MSVC to CMake configuration. +- Add Core Guidelines checking, limited to GSL Lite. +- Add test to compare empty to non-empty string span. +- Suppress test to compare empty string spans. +- Update Wandbox link for release 0.28.0. +- Update Wandbox link for release 0.27.0. + +version 0.27.0 2017-12-30 + +- Change extension of GSL Lite header file to .hpp with backwards compatibility via headers gsl.h and gsl/gsl-lite.h. See issue #94 (thanks to @AraHaan). +- Suppress several warnings from Microsoft's CppCoreCheck. See pull request #95 (thanks to @AraHaan). + +version 0.26.0 2017-12-09 + +- Rename final_act to final_action per issue #89. +- Make clang-tidy cppcoreguidelines checks pass per PR #91 (thanks to @poconbhui). +- Fix nullptr to gsl_nullptr in not_nul::get() per PR #90 (thanks to @poconbhui). +- Fix -Wshadow warning per PR #84 (thanks to @MikeLankamp). +- Add conan installation instructions and badge (thanks to @agauniyal). +- Add CMake install target per issue #85. + +version 0.25.0 2017-10-22 + +- Restrict owner<T> to pointers if possible, per issue #80. +- Introduce gsl_is_delete, per issue #81. +- Add deleted operators for not_null<>, per issue #82. +- Add more comparison operators for not_null<>, per issue #83. +- Use = default for not_null copy assignment/construction if available. +- Take parameter in not_null assignment by value as in ctor. + +version 0.24.0 2017-07-10 + +- Add try it online badge. +- Implement to_byte(), to_integer() for C++17 per issue #75 (thanks to David Mugnai, @cinghiale). + +version 0.23.0 2017-06-29 + +- Enable use of option -Wundef per issue #74. +- Update lest to version 1.30.1. +- Check macro via #ifdef if possibly undefined (support -Wundef). +- Fix check for make_unique(). +- Fix CMake compiler selection. +- Make struct definition nonlocal for C++98, C++03. +- Add not_null<> tests for member access and dereferencing. +- Add dereference operator to not_null<> per issue #73. +- Add compiler version information. +- Add constexpr to not_null<>. +- Report gsl_CPP11_OR_GREATER etc. + +version 0.22.0 2017-04-27 + +- Add operator<< for string_span (thanks to Magnus Bergsten, @Sillamacka). +- Fix conversion and sign-conversion warnings (thanks to Magnus Bergsten, @Sillamacka). +- Fix memory leak, which prevents tests to pass with address sanitizing (thanks to @Vladimir Rapatskiy). +- Fix order of add_compile_options() and its targets in CMakeLists.txt. +- Replace fail_fast's base with std::logic_error as per issue #69. +- Update lest_cpp03.hpp to version 1.29.1 (Fix above conversion and sign-conversion warnings). + +version 0.21.0 2016-11-28 + +- Add as_bytes() for basic_string_span<> (thanks to Magnus Bergsten, @Sillamacka). +- Fix: remove call to hash<std::size_t>(), undefined with Xcode on Mac OS X (issue #63, thanks to Dave Tallman). +- Fix: remove static from enum in integral_constant (thanks to Dave Tallman). +- Change t[g]-all.bat to test variations of C++ std/span index type/contract violation response. + +version 0.20.0 2016-11-18 + +- Remove used_length(), same as length() +- Rename bytes(), used_bytes() to size_bytes(), length_bytes() +- Make final_act<T> and final_act_return<T> useable with VC11/VS2012 (PR #61, thanks to @lm1458777) +- Fix fail_fast_assert() for gcc < 6 for no-throw/std::terminate() case (comment, thanks to @xsacha) +- Fix =default with gsl_noexcept for gcc < 6 for basic_string_span (PR #58, thanks to @xsacha) + +version 0.19.0 2016-11-17 + +- Rename as_span() creator functions to make_span() (issue #49). +- Add make_span() for gsl::shared_ptr, gsl::unique_ptr. +- Add section Algorithms to feature table. +- Remove maybe_null from feature table (M-GSL PR 123, 124, 126). + +version 0.18.0 2016-11-11 + +- Remove span::size_type, deprecated since 0.12.0. +- Add gsl_CONFIG_SPAN_INDEX_TYPE configuration macro; default size_t. +- Add span constructor for std::array<> const &. +- Add span constructor for std::unique_ptr, std::shared_ptr. +- Make span's unconstrained constructor disabled at default. + This enables construction from unique_ptr and shared_ptr. +- Prevent conversion warning [-Wconversion] +- Prevent old-style casts warning [-Wold-style-cast] +- Replace arr with &arr[0], not automatic decay (several). +- Update lest_cpp03.hpp to version 1.27.2 +- Fix noexcept with default ctors for GNUC < 4.9.0 (adapted PR #58, thanks to Dmitry Banschikov, @ubique). + +version 0.17.2 2016-11-10 + +- Use &arr[0], not automatic decay +- Workaround GNUC 5 throw constexpr bug +- Workaround for GNUC 5.2.0 failing two tests +- Use order: gsl_api inline gsl_constexpr type f() gsl_noexcept + +version 0.17.1 2016-11-09 + +- Fixes thanks to Magnus Bergsten, @Sillamacka: +- Marked several functions as constexpr. +- Fix: make gsl::fail_fast_assert() constexpr allowing Expects() from constexpr functions. +- Fix: prevent pointer decay to let remove_z() invoke wrong overload. +- Fix: remove span used in string_length(), it has two bound problems. + +version 0.17.0 2016-11-09 + +- Add free-standing as_bytes() and as_writable_bytes() as in M-GSL (PR #55, thanks to Dmitry Banschikov, @ubique). +- Member methods as_bytes() and as_writable_bytes() have been deprecated. + +version 0.16.1 2016-11-09 + +- Fix macro used with string_span comparison. + +version 0.16.0 2016-11-09 + +- Allow comparison with types that are convertible to string_span (issue #53, thanks to Magnus Bergsten, @Sillamacka). + +version 0.15.0 2016-11-09 + +- Add basic_string_span (issue #53, thanks to Magnus Bergsten, @Sillamacka). + +version 0.14.0 2016-11-03 + +- narrow() now uses std::terminate(), unless gsl_CONFIG_CONTRACT_VIOLATION_THROWS (issue #50, thanks to @Sp3EdeR) +- narrow_cast<>() now forwards its argument if possible (issue #44). + +version 0.13.0 2016-10-09 + +- Add on_return() and on_error() as experimental feature (gsl_FEATURE_EXPERIMENTAL_RETURN_GUARD). + +version 0.12.0 2016-10-08 + +- Fix test compilation with GCC 4.8.4. +- Remove span::value_type deprecated since version 0.9.0 (use element_type). +- Deprecate span::size_type (issue #42). +- Make span's stream output for tests more container-like. +- Make operations on byte C++11 constexpr except for op=() variants. +- Rename �Guidelines support library" to "Guideline -" (issue #39). +- Add tests for C++11 constexpr-ness. +- Add copy algorithm for span (issue #36). +- Add GSL version by Vicente J. Botet Escriba to Readme. + +version 0.11.0 2016-09-04 + +- Add missing byte comparisons (non-enum class case). +- Add missing gsl_noexcept to byte equality operator. + +version 0.10.1 2016-09-02 + +- Use struct with unsigned char for byte with pre-C++17 (issue #34). + +version 0.10.0 2016-08-31 + +- Remove operator bool() per issue #33. +- Remove deprecated gsl_CONFIG_THROWS_FOR_TESTING. +- Remove parentheses and allow lest to decompose span comparison expressions. +- Allow comparison of spans with a different element type or const-volatile-ness. +- Add gsl_CONFIG_ALLOWS_NONSTRICT_SPAN_COMPARISON for span comparison configuration. + +version 0.9.1 2016-08-25 + +- Move conditional inclusion of cstdint out of namespace gsl. + +version 0.9.0 2016-08-23 + +- Provide gsl/gsl header for compatibility with M-GSL. +- Add index_type to span while keeping size_type. +- Add gsl_noexcept to iterator creators begin() etc. +- Add at(std::initializer_list<T>, index). +- Add at(span<T>, index). +- Add call operator to span for element access as per p0122r3. +- Add test: empty spans compare equal as per p0122r3. +- Use span's size_type. +- Move at() to section utilities. +- Move comparison functions outside span. +- Deprecate span::value_type, use span::element_type per M-GSL, p0122r3. +- Remove non-const index operator, at(). + +version 0.8.0 2016-08-20 + +- Add operations for byte type. + +version 0.7.5 2016-08-08 + +- Fix to create empty subspan, enabling slicing off data until span is empty (PR #26, thanks to Janusz Chorko). + +version 0.7.4 2016-07-09 + +- Revert "Remove boundary check from operator[]()" of v0.7.3. + +version 0.7.3 2016-07-08 + +- Removed boundary check from operator[]() +- Changed indexing to return non-const reference and make it STL compliant (issue #23, thanks to @marton78) +- Made converting constructors public (issue #22, thanks to @marton78). + +version 0.7.2 2016-07-06 + +- Fixed as_span() for const arguments (thanks to Dave Tallman). + +version 0.7.1 2016-07-01 + +- Fixed with_container_t to be literal type (thanks to Dave Tallman). + +version 0.7.0 2016-06-30 + +- Added tagged construction from a container to span. +- Replaced gsl_CONFIG_ALLOWS_SPAN_CONTAINER_CTOR with gsl_CONFIG_ALLOWS_UNCONSTRAINED_SPAN_CONTAINER_CTOR + +version 0.6.1 2016-06-29 + +- Fixed library for the removal of _HAS_CPP0X in VS2015 Update 3 (Issue #21, thanks to @exjam) +- Added tests tagged [.stdlangauge], [.stdlibrary] to inspect various gsl_HAVE_... macros. +- Added tag [.stdc++] to test to inspect __cplusplus. +- Updated lest test framework to version 1.27.0. + +version 0.6.0 2016-06-25 + +- Renamed Final_act to final_act to follow standard library conventions. +- Fixed final_act to also work without copy-elision optimization, issue #19 (thanks to Marco Arena). + +version 0.5.0 2016-06-24 + +- Added compatibility with MS GSL symbolic names for contract violation response control. +- Added contract violation response control as suggested in N4415, Simple Contracts for C++. + +version 0.4.1 2016-06-23 + +- Added gsl_CONFIG_ALLOWS_SPAN_CONTAINER_CTOR for pre-C++11 (default: 1). +- Avoided std::distance() to support CUDA. +- Avoided shadowing according to the too-strict option -Wshadow of gcc before 4.8 (thanks to Dave Tallman). +- Removed comparisons of unsigned with zero. +- Fixed ensure_z() without length (thanks to Dave Tallman). + +version 0.4.0 2016-05-28 + +- Added support for CUDA compilation. + +version 0.3.2 2016-05-27 + +- Fixed compilation error in narrow() for VC11 (VS2012). + +version 0.3.1 2016-05-25 + +- Added test for construction of a span from another span of a compatible type. +- Changed view to span in specification. + +version 0.3.0 2016-05-24 + +- Added first(), last() and subspan(). +- Improved example 02-span.cpp (thanks to Dave Tallman). + +version 0.2.2 2016-05-23 + +- Fixed missing return in not_null copy-assignment (thanks to PVS-Studio). + +version 0.2.1 2016-05-23 + +- Added several tests. +- Added definition of gsl_HAVE_DEFAULT_FUNCTION_TEMPLATE_ARG. +- Prevented using default function template argument in span for pre-VS2013 (VC12). +- Fixed compile error with clang targeting MSVC, PR #17 (Thanks to @ned14). +- Fixed data access of empty container, PR #16 (Thanks to @realzhtw). + +version 0.2.0 2016-02-02 + +- Removed constructor span( U (&arr)[N], size_type size ), not part of M-GSL and in favour of: +- Changed constructor to span( pointer data, size_type size ), removing & from pointer & data (Thanks to @realzhtw). +- Added construction from an l-value for C++11 onwards. + +version 0.1.0 2016-02-02 + +- Added move-construction and move-assignment to span<>. + +version 0.0 2015-09-25 + +- Initial release. diff --git a/thirdparty/gsl-lite/LICENSE b/thirdparty/gsl-lite/LICENSE new file mode 100644 index 000000000..941611dea --- /dev/null +++ b/thirdparty/gsl-lite/LICENSE @@ -0,0 +1,24 @@ +The MIT License (MIT) + +Copyright (c) 2015-2019 Martin Moene +Copyright (c) 2019-2025 Moritz Beutel +Copyright (c) 2015-2018, 2025 Microsoft Corporation. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/thirdparty/gsl-lite/README.md b/thirdparty/gsl-lite/README.md new file mode 100644 index 000000000..4f178d36e --- /dev/null +++ b/thirdparty/gsl-lite/README.md @@ -0,0 +1,338 @@ +# *gsl-lite* + + +| metadata | build | packages | try online | +| -------- | ------ | -------- | ---------- | +| [](https://en.wikipedia.org/wiki/C%2B%2B#Standardization) <br> [](https://opensource.org/license/MIT) <br> [](https://github.com/gsl-lite/gsl-lite/releases) | [](https://dev.azure.com/gsl-lite/gsl-lite/_build/latest?definitionId=1&branchName=master) <br> [](https://ci.appveyor.com/project/gsl-lite/gsl-lite) | [](https://vcpkg.io/en/package/gsl-lite) <br> [](https://raw.githubusercontent.com/gsl-lite/gsl-lite/master/include/gsl-lite/gsl-lite.hpp) | [](https://gcc.godbolt.org/z/8jqq6P1G5) <br> [](https://wandbox.org/permlink/ZTwg9XJ9IEd4SptE) | + + +***gsl-lite*** is a portable, single-file, header-only library for defensive programming based on the [C++ Core Guidelines Support Library](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#S-gsl) specification. + + +## Contents + +- [Example usage](#example-usage) +- [In a nutshell](#in-a-nutshell) +- [License](#license) +- [Dependencies](#dependencies) +- [Installation and use](#installation-and-use) +- [Why *gsl-lite*?](#why-gsl-lite) +- [Features](#features) +- [Reference documentation](doc/Reference.md) +- [Migration guide](#migration-guide) +- [Using *gsl-lite* in libraries](#using-gsl-lite-in-libraries) +- [Reported to work with](#reported-to-work-with) +- [Version semantics](#version-semantics) +- [Contributing](#contributing) + + +## Example usage + +```c++ +#include <memory> +#include <utility> +#include <numeric> + +#include <gsl-lite/gsl-lite.hpp> + + +namespace my_lib { + + // Define this in your own namespace. + namespace gsl = ::gsl_lite; + + // `span<T[, Extent]>`: contiguous range with bounds checks + double mean( gsl::span<double const> values ) + { + // `gsl_Expects( cond )`: precondition check + gsl_Expects( !values.empty() ); + + double sum = std::accumulate( values.begin(), values.end(), 0. ); + + // `narrow_failfast<T>( u )`: checked numeric cast + double num = gsl::narrow_failfast<double>( std::ssize( values ) ); + + return sum / num; + } + + class Resource + { + ... + public: + Resource( std::size_t size ); + }; + + // Type-encoded precondition with `not_null<P>` + void consumeResource( gsl::not_null<std::unique_ptr<Resource>> resource ); + + // Type-encoded postcondition with `not_null<P>` + gsl::not_null<std::unique_ptr<Resource>> acquireResource( std::size_t size ) + { + // A flavor of `make_unique<T>()` which returns `not_null<std::unique_ptr<T>>` + return gsl::make_unique<Resource>( size ); + } + +} // namespace my_lib +``` + + +## In a nutshell + +*gsl-lite* strives to implement the [Guidelines Support Library specification](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#S-gsl) of the C++ Core Guidelines +maintained by the [Standard C++ Foundation](https://isocpp.org/). +The library is originally based on [Microsoft GSL](https://github.com/microsoft/gsl) and was adapted for C++98, C++03. It also works when compiled as C++11, C++14, C++17, C++20, or C++23. + +*gsl-lite* does not interfere with Microsoft GSL since both libraries live in different namespaces (`gsl_lite` vs. `gsl`). + +*gsl-lite* recognizes when it is compiled for the CUDA platform and decorates some functions with `__host__` and `__device__` accordingly. + + +## License + +*gsl-lite* uses the [MIT](LICENSE) license. + + +## Dependencies + +*gsl-lite* has no dependencies other than the [C++ standard library](http://en.cppreference.com/w/cpp/header). + + +## Installation and use + +The recommended way to consume *gsl-lite* in your CMake project is to use `find_package()` to locate the package `gsl-lite` +and `target_link_libraries()` to link to the imported target `gsl-lite::gsl-lite`: + +```cmake +cmake_minimum_required( VERSION 3.20 FATAL_ERROR ) + +project( my-program LANGUAGES CXX ) + +find_package( gsl-lite 1.0 REQUIRED ) + +add_executable( my-program main.cpp ) +target_compile_features( my-program PRIVATE cxx_std_17 ) +target_link_libraries( my-program PRIVATE gsl-lite::gsl-lite ) +``` + +*gsl-lite* is available via [Vcpkg](https://vcpkg.io/en/package/gsl-lite), [Conan](https://conan.io/center/recipes/gsl-lite), +and possibly other package managers. It may also be obtained with [CPM](https://github.com/cpm-cmake/CPM.cmake): +```cmake +CPMAddPackage( NAME gsl-lite VERSION 1.0.1 GITHUB_REPOSITORY gsl-lite/gsl-lite ) +``` +See the directories [example/with-CPM](https://github.com/gsl-lite/gsl-lite/tree/master/example/with-CPM) and +[example/with-Vcpkg](https://github.com/gsl-lite/gsl-lite/tree/master/example/with-Vcpkg) for example projects +that use CPM and Vcpkg, respectively, to obtain *gsl-lite*. + +Once the build system is set up, include the `<gsl-lite/gsl-lite.hpp>` header file to use *gsl-lite*: + +```c++ +// main.cpp + +#include <iostream> + +#include <gsl-lite/gsl-lite.hpp> + +void printCmdArgs( gsl_lite::span<gsl_lite::zstring const> cmdArgs ) +{ + gsl_Expects( !cmdArgs.empty() ); + + auto argsWithoutExeName = cmdArgs.subspan( 1 ); + for ( auto arg : argsWithoutExeName ) + { + std::cout << arg << "\n"; + } +} + +int main( int argc, char* argv[] ) +{ + auto numArgs = gsl_lite::narrow_failfast<std::size_t>( argc ); + auto cmdArgs = gsl_lite::span( argv, numArgs ); + printCmdArgs( cmdArgs ); +} +``` + + +## Why *gsl-lite*? + +*gsl-lite* is different from [Microsoft GSL](https://github.com/microsoft/gsl), the default implementation of the +[C++ Core Guidelines support library (GSL)](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines), in the following ways: + +- *gsl-lite* maintains support for older versions of C++ (C++98, C++03, C++11) and older compilers. + (see: [Reported to work with](#reported-to-work-with)) +- *gsl-lite* supports [CUDA](https://developer.nvidia.com/cuda-toolkit), and many of its features can be used in CUDA kernel code. +- [Contract and assertion checks](doc/Reference.md#contract-and-assertion-checks) are more fine-grained, and runtime enforcement is + [configurable](doc/Reference.md#contract-checking-configuration-macros). +- In *gsl-lite*, `not_null<P>` retains the copyability and movability of `P` and therefore may have a [*moved-from state*](doc/Reference.md#nullability-and-the-moved-from-state), + which Microsoft GSL [expressly disallows](https://github.com/microsoft/GSL/issues/1022#issuecomment-1022713632). + As a consequence, `not_null<std::unique_ptr<T>>` is movable in *gsl-lite* but not in Microsoft GSL. +- *gsl-lite* defines [feature testing macros](doc/Reference.md#feature-checking-macros) and [polyfills](doc/Reference.md#polyfills) useful for targeting multiple versions of C++. +- *gsl-lite* comes as a single-header library. + + +## Features + +See the [reference documentation](doc/Reference.md) for a detailed explanation of the features provided by *gsl-lite*, and +Section [GSL: Guidelines support library](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#S-gsl) of the C++ Core Guidelines +for the specification of the Guidelines support library. + + +Feature \\ library | GSL spec | MS GSL | *gsl‑lite* | Notes | +------------------------------------------------------------------------|:-----------:|:-------------:|:-------------------:|:-------| +[**Views:**](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#gslview-views) | | | | | +[`owner<>`](doc/Reference.md#ownerp-c11-and-higher) | ✓ | ✓ | ✓¹¹ | Annotate a raw pointer that carries ownership | +[`not_null<>`](doc/Reference.md#not_nullp) | ✓ | ✓ | ✓ | Annotate a (smart) pointer that must not be `nullptr`; enforces non-nullability at runtime<br>(cf. `strict_not_null<>` in Microsoft GSL) | +[`not_null_ic<>`](doc/Reference.md#not_null_icp) | - | ✓ | ✓ | Like `not_null<>` but allows implicit construction from nullable pointers<br>(cf. `not_null<>` in Microsoft GSL) | +[`make_unique<>()`](doc/Reference.md#not_nullp) | - | - | ✓¹¹ | Like [`std::make_unique<T>()`](https://en.cppreference.com/w/cpp/memory/unique_ptr/make_unique) but returns `not_null<std::unique_ptr<T>>` | +[`make_shared<>()`](doc/Reference.md#not_nullp) | - | - | ✓¹¹ | Like [`std::make_shared<T>()`](https://en.cppreference.com/w/cpp/memory/shared_ptr/make_shared) but returns `not_null<std::shared_ptr<T>>` | +[`span<>`](doc/Reference.md#safe-contiguous-ranges) | ✓ | ✓ | ✓ | Like [`std::span<>`](https://en.cppreference.com/w/cpp/container/span) but with bounds-checking | +[`zstring`<br>`czstring`](doc/Reference.md#string-type-aliases) | ✓ | ✓ | ✓ | Aliases for `char *` and `char const *` to be used for 0-terminated strings (C-style strings) | +[`wzstring`<br>`wczstring`](doc/Reference.md#string-type-aliases) | - | ✓ | ✓ | Aliases for `wchar_t *` and `wchar_t const *` to be used for 0-terminated strings (C-style strings) | +[**Assertions:**](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#gslassert-assertions) | | | | | +[`Expects()`](doc/Reference.md#contract-and-assertion-checks) | ✓ | ✓ | (✓) | Checks precondition at runtime<br>(only defined in [GSL compatibility mode](doc/Reference.md#gsl_feature_gsl_compatibility_mode0)) | +[`Ensures()`](doc/Reference.md#contract-and-assertion-checks) | ✓ | ✓ | (✓) | Checks precondition at runtime<br>(only defined in [GSL compatibility mode](doc/Reference.md#gsl_feature_gsl_compatibility_mode0)) | +[`gsl_Expects()`](doc/Reference.md#contract-and-assertion-checks) | - | - | ✓ | Checks precondition at runtime | +[`gsl_ExpectsDebug()`](doc/Reference.md#contract-and-assertion-checks) | - | - | ✓ | Checks precondition at runtime<br>unless [`NDEBUG`](https://en.cppreference.com/w/cpp/error/assert) is defined | +[`gsl_ExpectsAudit()`](doc/Reference.md#contract-and-assertion-checks) | - | - | ✓ | Checks precondition at runtime<br>if [audit mode](doc/Reference.md#runtime-enforcement) is enabled | +[`gsl_Ensures()`](doc/Reference.md#contract-and-assertion-checks) | - | - | ✓ | Checks postcondition at runtime | +[`gsl_EnsuresDebug()`](doc/Reference.md#contract-and-assertion-checks) | - | - | ✓ | Checks postcondition at runtime<br>unless [`NDEBUG`](https://en.cppreference.com/w/cpp/error/assert) is defined | +[`gsl_EnsuresAudit()`](doc/Reference.md#contract-and-assertion-checks) | - | - | ✓ | Checks postcondition at runtime<br>if [audit mode](doc/Reference.md#runtime-enforcement) is enabled | +[`gsl_Assert()`](doc/Reference.md#contract-and-assertion-checks) | - | - | ✓ | Checks invariant at runtime | +[`gsl_AssertDebug()`](doc/Reference.md#contract-and-assertion-checks) | - | - | ✓ | Checks invariant at runtime<br>unless [`NDEBUG`](https://en.cppreference.com/w/cpp/error/assert) is defined | +[`gsl_AssertAudit()`](doc/Reference.md#contract-and-assertion-checks) | - | - | ✓ | Checks invariant at runtime<br>if [audit mode](doc/Reference.md#runtime-enforcement) is enabled | +[**Utilities:**](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#gslutil-utilities) | | | | | +[`finally()`](doc/Reference.md#ad-hoc-resource-management-c11-and-higher) | ✓ | ✓ | ✓¹¹ | Returns an object that executes a given action in its destructor; use for ad hoc resource cleanup | +[`on_return()`](doc/Reference.md#ad-hoc-resource-management-c11-and-higher) | - | - | (✓¹¹) | Creates an object that executes a given action in its destructor if no exception occurred<br>([opt-in](doc/Reference.md#gsl_feature_experimental_return_guard0) feature) | +[`on_error()`](doc/Reference.md#ad-hoc-resource-management-c11-and-higher) | - | - | (✓¹¹) | Creates an object that executes a given action in its destructor if an exception was thrown<br>([opt-in](doc/Reference.md#gsl_feature_experimental_return_guard0) feature) | +[`at()`](doc/Reference.md#bounds-checked-element-access) | ✓ | ✓ | ✓ | Bounds-checked element access for C-style arrays and containers with random access | +[`index`](doc/Reference.md#integer-type-aliases) | ✓ | ✓ | ✓ | Signed integer type for indexes and subscripts | +[`dim`](doc/Reference.md#integer-type-aliases) | - | - | ✓ | Signed integer type for sizes | +[`stride`](doc/Reference.md#integer-type-aliases) | - | - | ✓ | Signed integer type for index strides | +[`diff`](doc/Reference.md#integer-type-aliases) | - | - | ✓ | Signed integer type for index differences | +[`narrow_cast<>()`](doc/Reference.md#narrow_castt-u-) | ✓ | ✓ | ✓ | Narrowing cast which tolerates lossy conversions; equivalent to `static_cast<>()` | +[`narrow<>()`](doc/Reference.md#narrowt-u-) | ✓ | ✓ | ✓ | Checked narrowing cast; throws `narrowing_error` if cast is lossy | +[`narrow_failfast<>()`](doc/Reference.md#narrow_failfastt-u-) | - | - | ✓ | Checked narrowing cast; fails assertion check if cast is lossy | + +¹¹: C++11 or newer required + + +## Migration guide + +Starting with v1.0, *gsl-lite* lives in the single header file `<gsl-lite/gsl-lite.hpp>`, and all its symbols reside in namespace +`gsl_lite`. By default, *gsl-lite* no longer defines a namespace `gsl` or the unprefixed `Expects()` and `Ensures()` macros for +precondition and postcondition checking. + +This change enables coexistence with [Microsoft GSL](https://github.com/microsoft/GSL) ([#194](https://github.com/gsl-lite/gsl-lite/issues/194)). + +### Adapting your code + +If you are migrating from *gsl-lite* v0.\*, adapt your code by referencing namespace `gsl_lite` rather than namespace `gsl`, and by +using the prefixed macros `gsl_Expects()` and `gsl_Ensures()` rather than the unprefixed macros `Expects()` and `Ensures()` for +precondition and postcondition checking. + +Note that *gsl-lite* v1 also changed the defaults for many of *gsl-lite*'s configuration options. See the +[v1.0.0 release notes](https://github.com/gsl-lite/gsl-lite/releases/tag/v1.0.0) for a comprehensive list of changes. +This should not affect you if you had already opted in to version-1 defaults by setting `gsl_CONFIG_DEFAULTS_VERSION=1` +or by linking to the `gsl::gsl-lite-v1` target in CMake. + +To reduce the pervasiveness of required changes, it can be useful to define a namespace alias inside your own namespace: + +```c++ +// my-lib.hpp + +#include <gsl-lite/gsl-lite.hpp> // instead of <gsl/gsl-lite.hpp> + +namespace my_lib { + + namespace gsl = ::gsl_lite; // convenience alias + + inline double median( gsl::span<double const> elements ) + { + gsl_Expects( !elements.empty() ); // instead of Expects() + ... + } + +} // namespace my_lib +``` + +### Using the GSL compatibility mode + +To minimize the impact of the breaking changes, *gsl-lite* introduces an optional *GSL compatibility mode* controlled by the +new configuration switch [`gsl_FEATURE_GSL_COMPATIBILITY_MODE`](doc/Reference.md#feature-selection-macros), which is is disabled +by default and can be enabled by defining `gsl_FEATURE_GSL_COMPATIBILITY_MODE=1`. + +If the GSL compatibility mode is enabled, *gsl-lite* additionally makes the following global definitions: +```c++ +namespace gsl = ::gsl_lite; +#define Expects( x ) gsl_Expects( x ) +#define Ensures( x ) gsl_Ensures( x ) +``` + +The GSL compatibility mode precludes the use of *gsl-lite* and Microsoft GSL in the same translation unit. Therefore, **do not use +the GSL compatibility mode when using *gsl-lite* in a public header file of a library.** (See notes on +[using *gsl-lite* in libraries](#using-gsl-lite-in-libraries) below.) + +The GSL compatibility mode causes no link-time interference between *gsl-lite* and as Microsoft GSL. Both libraries may be used in +the same project as long as no translation unit includes both at the same time. + +The legacy header file `<gsl/gsl-lite.hpp>` now forwards to `<gsl-lite/gsl-lite.hpp>` and implicitly enables the GSL compatibility mode. +When the legacy header is included, it emits a warning message that urges to either migrate to header `<gsl-lite/gsl-lite.hpp>`, +namespace `gsl_lite` and the prefixed contract checking macros `gsl_Expects()` and `gsl_Ensures()`, or to explicitly request GSL +compatibility by defining `gsl_FEATURE_GSL_COMPATIBILITY_MODE=1`. + + +## Using *gsl-lite* in libraries + +Many features of *gsl-lite* are very useful for defining library interfaces, for instance spans, contract checks, or `not_null<>`. + +*gsl-lite* can coexist with Microsoft GSL. However, the GSL compatibility mode of *gsl-lite* may cause interference with Microsoft GSL. +Also, *gsl-lite* is customizable through a large number of configuration options and switches. These configuration macros may affect the API and +ABI of *gsl-lite* in ways that renders it incompatible with other code. How *gsl-lite* is configured should be the prerogative of the consumer, +not the author, of a library. + +Therefore, when using *gsl-lite* in a library, please mind the following suggestions: + +- Do not define, or rely on, any of *gsl-lite*'s configuration options or switches when using *gsl-lite* in a library. +- In particular, do not enable the GSL compatibility mode. +- Do not use the legacy header file `<gsl/gsl-lite.hpp>`, which implicitly enables the GSL compatibility mode; use the header `<gsl-lite/gsl-lite.hpp>` instead. +- Use namespace `gsl_lite` rather than namespace `gsl`; if desired, define a `namespace gsl = ::gsl_lite;` alias in your own namespace. +- Use the prefixed contract checking macros `gsl_Expects()` and `gsl_Ensures()` rather than the unprefixed macros `Expects()` and `Ensures()`. + + +## Reported to work with + +The table below mentions the compiler versions and platforms *gsl-lite* is reported to work with. + +Compiler | OS | Platforms | Versions | CI | +--------------------:|:----------------|-----------|------------------:|----| +GCC | Linux | x64 | 4.7 and newer | [9, 10, 11, 12, 13, 14](https://dev.azure.com/gsl-lite/gsl-lite/_build?definitionId=1) | +GCC (MinGW) | Windows | x86, x64 | 4.8.4 and newer | | +GCC (DJGPP) | DOSBox, FreeDOS | x86 | 7.2 | | +GCC | MacOS | x64 | 6 and newer | [11, 12, 13, 14](https://dev.azure.com/gsl-lite/gsl-lite/_build?definitionId=1) | +Clang | Linux | x64 | 3.5 and newer | [11, 12, 13, 14, 15, 16, 17, 18, 19](https://dev.azure.com/gsl-lite/gsl-lite/_build?definitionId=1) | +Clang with libstdc++ | Linux | x64 | 11 and newer | [19](https://dev.azure.com/gsl-lite/gsl-lite/_build?definitionId=1) | +Clang | Windows | x64 | version shipped with VS | VS [2019, 2022](https://dev.azure.com/gsl-lite/gsl-lite/_build?definitionId=1) | +MSVC (Visual Studio) | Windows | x86, x64 | VS 2010 and newer | VS [2010, 2012, 2013, 2015, 2017](https://ci.appveyor.com/project/gsl-lite/gsl-lite), [2019, 2022](https://dev.azure.com/gsl-lite/gsl-lite/_build?definitionId=1) | +AppleClang (Xcode) | MacOS | x64 | 7.3 and newer | [14, 15, 16](https://dev.azure.com/gsl-lite/gsl-lite/_build?definitionId=1) | +NVCC (CUDA Toolkit) | Linux, Windows | x64 | 10.2 and newer | [12.8](https://dev.azure.com/gsl-lite/gsl-lite/_build?definitionId=1) | +ARMCC | | ARM | 5 and newer | | + + +## Version semantics + +*gsl-lite* follows [Semantic Versioning](https://semver.org/) guidelines. We maintain [API](https://en.wikipedia.org/wiki/Application_programming_interface) and +[ABI](https://en.wikipedia.org/wiki/Application_binary_interface) compatibility and avoid breaking changes in minor and patch releases. + +Development of *gsl-lite* happens in the `master` branch. Versioning semantics apply only to tagged releases: there is no stability guarantee between individual +commits in the `master` branch, that is, anything added since the last tagged release may be renamed, removed, or have the semantics changed without further notice. + +A minor-version release will be compatible (in both ABI and API) with the previous minor-version release. Thus, once a change is released, it becomes part of the API. + +Some of the [configuration options](doc/Reference.md#configuration-options-and-switches) may affect the API and ABI of *gsl-lite*. + + +## Contributing + +Contributions to *gsl-lite* through [pull requests](https://github.com/gsl-lite/gsl-lite/pulls) or [issues](https://github.com/gsl-lite/gsl-lite/issues) are welcome. + +*gsl-lite* comes with a test suite that uses an included, slightly modified copy of the [*lest* test framework](https://github.com/martinmoene/lest). +To build *gsl-lite*'s test suite, enable the CMake build option `GSL_LITE_OPT_BUILD_TESTS` when configuring the project. diff --git a/thirdparty/gsl-lite/_config.yml b/thirdparty/gsl-lite/_config.yml new file mode 100644 index 000000000..e0147566c --- /dev/null +++ b/thirdparty/gsl-lite/_config.yml @@ -0,0 +1,6 @@ +description: ISO C++ Core Guidelines Library implementation for C++98, C++11, and later +remote_theme: jekyll/minima@0b7ca6b +plugins: + - jekyll-remote-theme +minima: + skin: auto diff --git a/thirdparty/gsl-lite/_includes/footer.html b/thirdparty/gsl-lite/_includes/footer.html new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/thirdparty/gsl-lite/_includes/footer.html diff --git a/thirdparty/gsl-lite/_includes/nav-items.html b/thirdparty/gsl-lite/_includes/nav-items.html new file mode 100644 index 000000000..30ee89f8f --- /dev/null +++ b/thirdparty/gsl-lite/_includes/nav-items.html @@ -0,0 +1,4 @@ +<div class="nav-items"> + <a class="nav-item" href="https://gsl-lite.github.io/gsl-lite/doc/Reference.html">Reference documentation</a> + <a class="nav-item" href="https://github.com/gsl-lite/gsl-lite">GitHub repository</a> +</div> diff --git a/thirdparty/gsl-lite/_layouts/home.html b/thirdparty/gsl-lite/_layouts/home.html new file mode 100644 index 000000000..c65a9b020 --- /dev/null +++ b/thirdparty/gsl-lite/_layouts/home.html @@ -0,0 +1,64 @@ +--- +layout: base +--- + +<div class="home"> + + {{ content }} + + + {% if site.paginate %} + {% assign posts = paginator.posts %} + {% else %} + {% assign posts = site.posts %} + {% endif %} + + + {%- if posts.size > 0 -%} + {%- if page.list_title -%} + <h2 class="post-list-heading">{{ page.list_title }}</h2> + {%- endif -%} + <ul class="post-list"> + {%- assign date_format = site.minima.date_format | default: "%b %-d, %Y" -%} + {%- for post in posts -%} + <li> + <span class="post-meta">{{ post.date | date: date_format }}</span> + <h3> + <a class="post-link" href="{{ post.url | relative_url }}"> + {{ post.title | escape }} + </a> + </h3> + {%- if site.minima.show_excerpts -%} + {{ post.excerpt }} + {%- endif -%} + </li> + {%- endfor -%} + </ul> + + {% if site.paginate %} + <div class="pager"> + <ul class="pagination"> + {%- if paginator.previous_page %} + <li> + <a href="{{ paginator.previous_page_path | relative_url }}" class="previous-page" title="Go to Page {{ paginator.previous_page }}"> + {{ paginator.previous_page }} + </a> + </li> + {%- else %} + <li><div class="pager-edge">•</div></li> + {%- endif %} + <li><div class="current-page">{{ paginator.page }}</div></li> + {%- if paginator.next_page %} + <li> + <a href="{{ paginator.next_page_path | relative_url }}" class="next-page" title="Go to Page {{ paginator.next_page }}"> + {{ paginator.next_page }} + </a> + </li> + {%- else %} + <li><div class="pager-edge">•</div></li> + {%- endif %} + </ul> + </div> + {%- endif %} + {%- endif -%} +</div> diff --git a/thirdparty/gsl-lite/_layouts/page.html b/thirdparty/gsl-lite/_layouts/page.html new file mode 100644 index 000000000..43851a089 --- /dev/null +++ b/thirdparty/gsl-lite/_layouts/page.html @@ -0,0 +1,10 @@ +--- +layout: base +--- +<article class="post"> + + <div class="post-content"> + {{ content }} + </div> + +</article> diff --git a/thirdparty/gsl-lite/_sass/minima/custom-variables.scss b/thirdparty/gsl-lite/_sass/minima/custom-variables.scss new file mode 100644 index 000000000..387f596b2 --- /dev/null +++ b/thirdparty/gsl-lite/_sass/minima/custom-variables.scss @@ -0,0 +1,7 @@ +$content-width: 900px; + +$on-palm: 600px; +$on-laptop: 900px; + +$on-medium: $on-palm; +$on-large: $on-laptop; diff --git a/thirdparty/gsl-lite/appveyor.yml b/thirdparty/gsl-lite/appveyor.yml new file mode 100644 index 000000000..109802dd7 --- /dev/null +++ b/thirdparty/gsl-lite/appveyor.yml @@ -0,0 +1,51 @@ +version: "{branch} #{build}" + +shallow_clone: true + +image: + #- Visual Studio 2019 + - Visual Studio 2017 + - Visual Studio 2015 + +environment: + matrix: + # VS 2019 and newer are tested with Azure Pipelines + #- generator: "Visual Studio 16 2019" + - generator: "Visual Studio 15 2017" + - generator: "Visual Studio 14 2015" + - generator: "Visual Studio 12 2013" + - generator: "Visual Studio 11 2012" + - generator: "Visual Studio 10 2010" + +configuration: + - Debug + #- Release + +platform: + - Win32 + - x64 + +matrix: + fast_finish: false + exclude: + - image: Visual Studio 2017 + generator: "Visual Studio 12 2013" + - image: Visual Studio 2017 + generator: "Visual Studio 11 2012" + - image: Visual Studio 2017 + generator: "Visual Studio 10 2010" + - image: Visual Studio 2015 + generator: "Visual Studio 15 2017" + - image: Visual Studio 2015 + generator: "Visual Studio 14 2015" + +before_build: + - mkdir build && cd build + - cmake -A %platform% -G "%generator%" -DGSL_LITE_OPT_BUILD_TESTS=ON -DGSL_LITE_OPT_BUILD_EXAMPLES=ON .. + +build_script: + #- cmake --build . --config %configuration% -- -verbosity:normal + - cmake --build . --config %configuration% -- -verbosity:minimal + +test_script: + - ctest --output-on-failure -C %configuration% diff --git a/thirdparty/gsl-lite/azure-pipelines.yml b/thirdparty/gsl-lite/azure-pipelines.yml new file mode 100644 index 000000000..5fd28243d --- /dev/null +++ b/thirdparty/gsl-lite/azure-pipelines.yml @@ -0,0 +1,205 @@ + +variables: + System.Debug: true + +trigger: +- master +- mr/* + +pr: +- master + +resources: + repositories: + - repository: CImakeshift + type: github + name: mbeutel/CImakeshift + endpoint: gsl-lite + +jobs: +- template: azure-pipelines/cmake.yml@CImakeshift + parameters: + cache: False + cmakeBuildConfigurations: [Debug] + cmakeConfigArgs: '-DGSL_LITE_OPT_BUILD_TESTS=ON -DGSL_LITE_OPT_BUILD_EXAMPLES=ON' + cmakeTestArgs: '--exclude-regex cuda' # do not run CUDA tests + + targets: + + # put a set of representative (and slow) jobs first + + - os: Linux + cxxCompiler: GCC + cxxCompilerVersions: [14] + cmakeBuildConfigurations: [Debug, RelWithDebInfo] + platforms: [x64] + tag: 'memcheck' + postSetupSteps: + - bash: | + sudo apt install valgrind + # suppress AVX/AVX2 paths because there are apparent false positives in glibc's AVX2-optimized memcmp routines + # (cf. https://sourceware.org/bugzilla/show_bug.cgi?id=22954, https://bugs.kde.org/show_bug.cgi?id=397083) + echo "##vso[task.setvariable variable=GLIBC_TUNABLES]glibc.cpu.hwcaps=-AVX2_Usable,-AVX_Usable,-AVX_Fast_Unaligned_Load" + displayName: 'Install Valgrind' + # Make Valgrind return a non-zero exit code when errors occur in order to make the job fail. + # Also, enforce DWARF version 4 because Valgrind cannot read DWARF version 5 yet (cf. https://bugs.kde.org/show_bug.cgi?id=452758). + cmakeConfigArgs: '-DGSL_LITE_OPT_BUILD_TESTS=ON -DCMAKE_CXX_FLAGS="-gdwarf-4" -DMEMORYCHECK_COMMAND_OPTIONS="--error-exitcode=1 --leak-check=full"' + cmakeBuildArgs: '<cmakeBuildArgs> --target gsl-lite-v1-cpp20.t' + cmakeTestArgs: '<cmakeTestArgs> --test-action memcheck --tests-regex gsl-lite-v1-cpp20' + + - os: Linux + cxxCompiler: GCC + cxxCompilerVersions: [14] + cmakeBuildConfigurations: [Debug, RelWithDebInfo] + cudaCompiler: NVCC + cudaCompilerVersions: [12_8] + platforms: [x64] + cmakeConfigArgs: '-DGSL_LITE_OPT_BUILD_CUDA_TESTS=ON' + + # CImakeshift doesn't currently support Clang-CUDA. + #- os: Linux + # cxxCompiler: Clang + # cxxCompilerVersions: [13] + # cmakeBuildConfigurations: [Debug, RelWithDebInfo] + # cudaCompiler: Clang + # cudaCompilerVersions: [13] + # platforms: [x64] + # cmakeConfigArgs: '-DGSL_LITE_OPT_BUILD_CUDA_TESTS=ON' + + - os: Linux + cxxCompiler: Clang + cxxCompilerVersions: [19] + cmakeBuildConfigurations: [Debug, RelWithDebInfo] + platforms: [x64] + tag: 'memcheck' + postSetupSteps: + - bash: | + sudo apt install valgrind + # suppress AVX/AVX2 paths because there are apparent false positives in glibc's AVX2-optimized memcmp routines + # (cf. https://sourceware.org/bugzilla/show_bug.cgi?id=22954, https://bugs.kde.org/show_bug.cgi?id=397083) + echo "##vso[task.setvariable variable=GLIBC_TUNABLES]glibc.cpu.hwcaps=-AVX2_Usable,-AVX_Usable,-AVX_Fast_Unaligned_Load" + displayName: 'Install Valgrind' + # Make Valgrind return a non-zero exit code when errors occur in order to make the job fail. + # Also, enforce DWARF version 4 because Valgrind cannot read DWARF version 5 yet (cf. https://bugs.kde.org/show_bug.cgi?id=452758). + cmakeConfigArgs: '-DGSL_LITE_OPT_BUILD_TESTS=ON -DCMAKE_CXX_FLAGS="-gdwarf-4" -DMEMORYCHECK_COMMAND_OPTIONS="--error-exitcode=1 --leak-check=full"' + cmakeBuildArgs: '<cmakeBuildArgs> --target gsl-lite-v0-cpp20.t gsl-lite-v1-cpp20.t' + cmakeTestArgs: '<cmakeTestArgs> --test-action memcheck --tests-regex gsl-lite-v[0-1]-cpp20' + + - os: Windows + cxxCompiler: MSVC + cxxCompilerVersions: [VS2022] + cmakeGenerator: 'MSBuild' # required for CppCoreCheck + cmakeBuildConfigurations: [Debug, RelWithDebInfo] + platforms: [x86, x64] + cmakeConfigArgs: '<cmakeConfigArgs> -DGSL_LITE_OPT_BUILD_STATIC_ANALYSIS_DEMOS=ON' + cmakeBuildArgs: '<cmakeBuildArgs> --target gsl-lite-v1-cpplatest.t gsl-lite-v1-cpplatest-CppCoreCheck' + cmakeTestArgs: '<cmakeTestArgs> --tests-regex gsl-lite-v1-cpplatest' + + - os: Windows + cxxCompiler: Clang + cxxCompilerVersions: [VS2019, VS2022] + cmakeBuildConfigurations: [Debug, RelWithDebInfo] + platforms: [x86, x64] + cmakeBuildArgs: '<cmakeBuildArgs> --target gsl-lite-v1-cpplatest.t' + cmakeTestArgs: '<cmakeTestArgs> --tests-regex gsl-lite-v1-cpplatest' + + - os: Windows + cxxCompiler: MSVC + cxxCompilerVersions: [VS2022] + cudaCompiler: NVCC + cudaCompilerVersions: [12_8] + cmakeBuildConfigurations: [Debug, RelWithDebInfo] + platforms: [x64] + cmakeConfigArgs: '-DGSL_LITE_OPT_BUILD_CUDA_TESTS=ON' + + - os: MacOS + cxxCompiler: AppleClang + cxxCompilerVersions: [16] + cmakeBuildConfigurations: [Debug, RelWithDebInfo] + platforms: [x64] + cmakeBuildArgs: '<cmakeBuildArgs> --target gsl-lite-v1-cpp17.t' + cmakeTestArgs: '<cmakeTestArgs> --tests-regex gsl-lite-v1-cpp17' + + # GCC 4.7, 4.8, 4.9, 5, and 6 are tested with Travis + #- os: Linux + # cxxCompiler: GCC + # cxxCompilerVersions: [5] + # platforms: [x64] + + - os: Linux + cxxCompiler: GCC + cxxCompilerVersions: [9, 10, 11, 12, 13] + platforms: [x64] + + - os: Linux + cxxCompiler: GCC + cxxCompilerVersions: [14] + cxxStandardLibraryDebugMode: true + cxxSanitizers: [AddressSanitizer, UndefinedBehaviorSanitizer] + platforms: [x64] + tag: 'sanitize' + cmakeConfigArgs: '-DGSL_LITE_OPT_BUILD_TESTS=ON' + cmakeBuildArgs: '<cmakeBuildArgs> --target gsl-lite-v0-cpp17.t gsl-lite-v1-cpp17.t' + cmakeTestArgs: '<cmakeTestArgs> --tests-regex gsl-lite-v[0-1]-cpp17' + + # Clang 3.5, 3.6, 3.7, 3.8, and 3.9, 4, and 5 are tested with Travis + #- os: Linux + # cxxCompiler: Clang + # cxxCompilerVersions: [4] + # platforms: [x64] + + - os: Linux + cxxCompiler: Clang + cxxCompilerVersions: [11, 12, 13, 14, 15, 16, 17, 18] + platforms: [x64] + + - os: Linux + cxxCompiler: Clang + cxxCompilerVersions: [19] + cxxStandardLibraryDebugMode: true + cxxSanitizers: [AddressSanitizer, UndefinedBehaviorSanitizer, ImplicitIntegerArithmeticValueChange] + platforms: [x64] + tag: 'sanitize' + cmakeConfigArgs: '-DGSL_LITE_OPT_BUILD_TESTS=ON' + cmakeBuildArgs: '<cmakeBuildArgs> --target gsl-lite-v0-cpp17.t gsl-lite-v1-cpp17.t' + cmakeTestArgs: '<cmakeTestArgs> --tests-regex gsl-lite-v[0-1]-cpp17' + + - os: Linux + cxxCompiler: Clang + cxxCompilerVersions: [19] + cxxStandardLibrary: libstdc++ + platforms: [x64] + tag: 'libstdc++' + + - os: Linux + cxxCompiler: GCC + cxxCompilerVersions: [11] + cudaCompiler: NVCC + cudaCompilerVersions: [12_6] + platforms: [x64] + cmakeConfigArgs: '-DGSL_LITE_OPT_BUILD_CUDA_TESTS=ON' + + # VS 2010, 2012, 2013, 2015, and 2017 are tested with AppVeyor + + - os: Windows + cxxCompiler: MSVC + cxxCompilerVersions: [VS2019] + cudaCompiler: NVCC + cudaCompilerVersions: [11_8, 12_1] + platforms: [x64] + cmakeConfigArgs: '-DGSL_LITE_OPT_BUILD_CUDA_TESTS=ON' + + - os: Windows + cxxCompiler: MSVC + cxxCompilerVersions: [VS2019, VS2022] + platforms: [x86, x64] + + - os: MacOS + cxxCompiler: GCC + cxxCompilerVersions: [11, 12, 13, 14] + platforms: [x64] + + - os: MacOS + cxxCompiler: AppleClang + cxxCompilerVersions: [14, 15, 16] + platforms: [x64] diff --git a/thirdparty/gsl-lite/cmake/CommonPresets.json b/thirdparty/gsl-lite/cmake/CommonPresets.json new file mode 100644 index 000000000..9e3c5314a --- /dev/null +++ b/thirdparty/gsl-lite/cmake/CommonPresets.json @@ -0,0 +1,245 @@ +{ + // Collection of generally useful CMake configuration presets. + // Version 0.1.0β + // The contents of this file are in the public domain. + // (Moritz Beutel, 2025) + "version": 7, + "configurePresets": [ + { + "name": "use Vcpkg", + "hidden": true, + "toolchainFile": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake" + }, + + { + "name": "compiler presets", + "hidden": true, + "environment": { + "_CFLAGS": "$penv{CFLAGS} $env{_PRESET_CFLAGS} $env{_USE_PRESET_ASAN} $env{_USE_PRESET_UBSAN} $env{_USE_PRESET_TSAN} $env{_USE_PRESET_STDLIB}", + "_CXXFLAGS": "$penv{CXXFLAGS} $env{_PRESET_CXXFLAGS} $env{_USE_PRESET_ASAN} $env{_USE_PRESET_UBSAN} $env{_USE_PRESET_TSAN} $env{_USE_PRESET_STDLIB} $env{_USE_PRESET_DEBUGCHECKS}", + "_CUDAFLAGS": "$penv{CUDAFLAGS} $env{_PRESET_CUDAFLAGS} $env{_CUDA_USE_PRESET_STDLIB} $env{_USE_PRESET_DEBUGCHECKS}", + "CFLAGS": "$env{_CFLAGS}", + "CXXFLAGS": "$env{_CXXFLAGS}", + "CUDAFLAGS": "$env{_CUDAFLAGS}", + "MY_COMPILE_OPTIONS": "$env{_USE_PRESET_WARN};$env{_USE_PRESET_WARNERR}" + } + }, + + { + // "CI" covers AppVeyor, GitHub Actions, GitLab CI, Travis CI, and possibly others. + "name": "CI", + "hidden": true, + "condition": { + "type": "notEquals", + "lhs": "$env{CI}$env{CIRCLECI}$env{TF_BUILD}", + "rhs": "" + } + }, + + { + // For MSVC, enable UTF-8 source file encoding, the highest warning level, and some additional warnings: + // W44062: enumerator 'identifier' in a switch of enum 'enumeration' is not handled + // W44242: 'identifier': conversion from 'type1' to 'type2', possible loss of data + // W44254: 'operator': conversion from 'type1' to 'type2', possible loss of data + // W44265: 'class': class has virtual functions, but destructor is not virtual + "name": "MSVC presets", + "hidden": true, + "inherits": "compiler presets", + "environment": { + "_PRESET_CFLAGS": "/utf-8", + "_PRESET_CXXFLAGS": "/utf-8", + "_PRESET_CUDAFLAGS": "-Xcompiler=/utf-8", + "_PRESET_WARN": "$<$<COMPILE_LANGUAGE:C,CXX>:/permissive-;/W4;/w44062;/w44242;/w44254;/w44265>$<$<COMPILE_LANGUAGE:CUDA>:-Xcompiler=/permissive-,/W4,/w44062,/w44242,/w44254,/w44265>", + "_PRESET_WARNERR": "$<$<COMPILE_LANGUAGE:C,CXX>:/WX>$<$<COMPILE_LANGUAGE:CUDA>:-Xcompiler=/WX>", + "_PRESET_ASAN": "/fsanitize=address", + "_PRESET_UBSAN": "/fsanitize=undefined", // not currently supported + "_PRESET_TSAN": "/fsanitize=thread", // not currently supported + "_PRESET_DEBUGCHECKS": "/D_ITERATOR_DEBUG_LEVEL=1" + }, + "condition": { + "type": "equals", + "lhs": "${hostSystemName}", + "rhs": "Windows" + } + }, + { + // For clang-cl, use the same general presets as for MSVC with some minor changes. + "name": "clang-cl presets", + "hidden": true, + "inherits": "compiler presets", + "environment": { + "_PRESET_CFLAGS": "/utf-8", + "_PRESET_CXXFLAGS": "/utf-8", + "_PRESET_CUDAFLAGS": "-Xcompiler=/utf-8", + "_PRESET_WARN": "$<$<COMPILE_LANGUAGE:C,CXX>:/permissive-;/W4;/w44062;/w44242;/w44254;/w44265>$<$<COMPILE_LANGUAGE:CUDA>:-Xcompiler=/permissive-,/W4,/w44062,/w44242,/w44254,/w44265>", + "_PRESET_WARNERR": "$<$<COMPILE_LANGUAGE:C,CXX>:/WX>$<$<COMPILE_LANGUAGE:CUDA>:-Xcompiler=/WX>", + "_PRESET_ASAN": "/fsanitize=address", + "_PRESET_UBSAN": "-fsanitize=undefined -fsanitize-trap=undefined -fsanitize=implicit-integer-arithmetic-value-change", + "_PRESET_TSAN": "-fsanitize=thread", // not currently supported + "_PRESET_DEBUGCHECKS": "/D_ITERATOR_DEBUG_LEVEL=1" + }, + "condition": { + "type": "equals", + "lhs": "${hostSystemName}", + "rhs": "Windows" + } + }, + { + // For GCC, enable the highest warning level and pedantic mode. + "name": "GCC presets", + "hidden": true, + "inherits": "compiler presets", + "environment": { + "_PRESET_CFLAGS": "", + "_PRESET_CXXFLAGS": "", + "_PRESET_CUDAFLAGS": "", + "_PRESET_WARN": "$<$<COMPILE_LANGUAGE:C,CXX>:-Wall;-Wextra;-pedantic>$<$<COMPILE_LANGUAGE:CUDA>:-Xcompiler=-Wall,-Wextra,-pedantic>", + "_PRESET_WARNERR": "$<$<COMPILE_LANGUAGE:C,CXX>:-Werror>", // avoid -Werror for CUDA host compilers for now + "_PRESET_ASAN": "-fsanitize=address -fno-omit-frame-pointer", + "_PRESET_UBSAN": "-fsanitize=undefined -fno-omit-frame-pointer -fsanitize-undefined-trap-on-error", + "_PRESET_TSAN": "-fsanitize=thread", + "_PRESET_DEBUGCHECKS": "-D_GLIBCXX_DEBUG" + } + }, + { + // For Clang, enable the highest warning level and pedantic mode. + "name": "Clang presets", + "hidden": true, + "inherits": "compiler presets", + "environment": { + "_PRESET_CFLAGS": "", + "_PRESET_CXXFLAGS": "", + "_PRESET_CUDAFLAGS": "", + "_PRESET_WARN": "$<$<COMPILE_LANGUAGE:C,CXX>:-Wall;-Wextra;-pedantic>$<$<COMPILE_LANGUAGE:CUDA>:-Xcompiler=-Wall,-Wextra,-pedantic>", + "_PRESET_WARNERR": "$<$<COMPILE_LANGUAGE:C,CXX>:-Werror>", // avoid -Werror for CUDA host compilers for now + "_PRESET_ASAN": "-fsanitize=address -fno-omit-frame-pointer", + "_PRESET_UBSAN": "-fsanitize=undefined -fno-omit-frame-pointer -fsanitize-trap=undefined -fsanitize=implicit-integer-arithmetic-value-change", + "_PRESET_TSAN": "-fsanitize=thread", + // cf. https://libcxx.llvm.org/Hardening.html + "_PRESET_DEBUGCHECKS": "-D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_DEBUG" + } + }, + + { + "name": "ASan", + "hidden": true, + "inherits": "compiler presets", + "environment": { + "_USE_PRESET_ASAN": "$env{_PRESET_ASAN}" + } + }, + { + "name": "UBSan", + "hidden": true, + "inherits": "compiler presets", + "environment": { + "_USE_PRESET_UBSAN": "$env{_PRESET_UBSAN}" + } + }, + { + "name": "TSan", + "hidden": true, + "inherits": "compiler presets", + "environment": { + "_USE_PRESET_TSAN": "$env{_PRESET_TSAN}" + } + }, + { + "name": "library debug checks", + "hidden": true, + "inherits": "compiler presets", + "environment": { + "_USE_PRESET_DEBUGCHECKS": "$env{_PRESET_DEBUGCHECKS} $env{_PRESET_DEBUGCHECKS2}" + } + }, + { + "name": "high warning level", + "hidden": true, + "inherits": "compiler presets", + "environment": { + "_USE_PRESET_WARN": "$env{_PRESET_WARN}" + } + }, + { + "name": "warnings as errors", + "hidden": true, + "inherits": "compiler presets", + "environment": { + "_USE_PRESET_WARNERR": "$env{_PRESET_WARNERR}" + } + }, + + { + "name": "libstdc++ for Clang", + "hidden": true, + "inherits": "compiler presets", + "environment": { + "_USE_PRESET_STDLIB": "-stdlib=libstdc++", + "_CUDA_USE_PRESET_STDLIB": "-Xcompiler=-stdlib=libstdc++", + "_PRESET_DEBUGCHECKS2": "-D_GLIBCXX_DEBUG" + } + }, + + { + "name": "force MSVC", + "hidden": true, + "inherits": "MSVC presets", + "environment": { + "CC": "cl", + "CXX": "cl" + }, + "condition": { + "type": "equals", + "lhs": "${hostSystemName}", + "rhs": "Windows" + } + }, + { + "name": "force clang-cl", + "hidden": true, + "inherits": "clang-cl presets", + "environment": { + "CC": "clang-cl", + "CXX": "clang-cl" + }, + "condition": { + "type": "equals", + "lhs": "${hostSystemName}", + "rhs": "Windows" + } + }, + { + "name": "force GCC", + "hidden": true, + "inherits": "GCC presets", + "environment": { + "CC": "gcc", + "CXX": "g++" + } + }, + { + "name": "force Clang", + "hidden": true, + "inherits": "Clang presets", + "environment": { + "CC": "clang", + "CXX": "clang++" + } + } + ], + "buildPresets": [ + ], + "testPresets": [ + { + "name": "defaults", + "hidden": true, + "output": { + "outputOnFailure": true + }, + "execution": { + "noTestsAction": "error", + "stopOnFailure": true + } + } + ] +} diff --git a/thirdparty/gsl-lite/cmake/InstallBasicPackageFiles.cmake b/thirdparty/gsl-lite/cmake/InstallBasicPackageFiles.cmake new file mode 100644 index 000000000..077b95d5f --- /dev/null +++ b/thirdparty/gsl-lite/cmake/InstallBasicPackageFiles.cmake @@ -0,0 +1,684 @@ +# SPDX-FileCopyrightText: 2012-2021 Istituto Italiano di Tecnologia (IIT) +# SPDX-License-Identifier: BSD-3-Clause + +#[=======================================================================[.rst: +InstallBasicPackageFiles +------------------------ + +A helper module to make your package easier to be found by other +projects. + + +.. command:: install_basic_package_files + +Create and install a basic version of cmake config files for your +project:: + + install_basic_package_files(<Name> + COMPATIBILITY <compatibility> + [VERSION <version>] + [ARCH_INDEPENDENT] + [NO_EXPORT | EXPORT <export>] # (default = "EXPORT <Name>") + [NO_SET_AND_CHECK_MACRO] + [NO_CHECK_REQUIRED_COMPONENTS_MACRO] + [VARS_PREFIX <prefix>] # (default = "<Name>") + [EXPORT_DESTINATION <destination>] + [INSTALL_DESTINATION <destination>] + [NAMESPACE <namespace>] # (default = "<Name>::") + [EXTRA_PATH_VARS_SUFFIX path1 [path2 ...]] + [CONFIG_TEMPLATE <file>] + [UPPERCASE_FILENAMES | LOWERCASE_FILENAMES] + [DEPENDENCIES <dependency1> "<dependency2> [...]" ...] + [PRIVATE_DEPENDENCIES <dependency1> "<dependency2> [...]" ...] + [INCLUDE_FILE <file> | INCLUDE_CONTENT <content>] + [COMPONENT <component>] # (default = "<Name>") + ) + +Depending on ``UPPERCASE_FILENAMES`` and ``LOWERCASE_FILENAMES``, this +function generates 3 files: + + - ``<Name>ConfigVersion.cmake`` or ``<name>-config-version.cmake`` + - ``<Name>Config.cmake`` or ``<name>-config.cmake`` + - ``<Name>Targets.cmake`` or ``<name>-targets.cmake`` + +If neither ``UPPERCASE_FILENAMES`` nor ``LOWERCASE_FILENAMES`` is +set, a file ``<Name>Config.cmake.in`` or +``<name>-config.cmake.in`` is searched, and the convention +is chosed according to the file found. If no file was found, the +uppercase convention is used. + +The ``DEPENDENCIES`` argument can be used to set a list of dependencies +that will be searched using the :cmake:command:`find_dependency` command +from the :module:`CMakeFindDependencyMacro` module. +Dependencies can be followed by any of the possible +:cmake:command:`find_dependency` argument. +In this case, all the arguments must be specified within double quotes (e.g. +``"<dependency> 1.0.0 EXACT"``, or ``"<dependency> CONFIG"``). +The ``PRIVATE_DEPENDENCIES`` argument is similar to ``DEPENDENCIES``, but +these dependencies are included only when :variable:`BUILD_SHARED_LIBS` is +``OFF``. +If a libraries is declared ``STATIC``, ``OBJECT`` or ``INTERFACE``, and they +link to some dependency, these should be added using the ``DEPENDENCIES`` +argument, since the ``PRIVATE_DEPENDENCIES`` argument would work only when +:variable:`BUILD_SHARED_LIBS` is disabled. + +When using a custom template file, the ``@PACKAGE_DEPENDENCIES@`` +string is replaced with the code checking for the dependencies +specified by these two argument. + +If the ``ARCH_INDEPENDENT`` option is enabled, the installed package version +will be considered compatible even if it was built for a different +architecture than the requested architecture. + +Each file is generated twice, one for the build directory and one for +the installation directory. The ``INSTALL_DESTINATION`` argument can be +passed to install the files in a location different from the default +one (``${CMAKE_INSTALL_DATADIR}/cmake/${Name}`` if the ``ARCH_INDEPENDENT`` +option is enabled, ``${CMAKE_INSTALL_LIBDIR}/cmake/${Name}`` otherwise). +The ``EXPORT_DESTINATION`` argument can be passed to +generate the files in the build tree in a location different from the default +one (``CMAKE_BINARY_DIR``). If this is a relative path, it is +considered relative to the ``CMAKE_CURRENT_BINARY_DIR`` directory. + +The build directory is exported to the CMake user package registry if the +build option ``CMAKE_EXPORT_PACKAGE_REGISTRY`` is set. + +The ``<Name>ConfigVersion.cmake`` file is generated using +:cmake:command:`write_basic_package_version_file`. The ``VERSION``, +``COMPATIBILITY``, and ``ARCH_INDEPENDENT``arguments are passed to this +function. + +``VERSION`` shall be in the form ``<major>[.<minor>[.<patch>[.<tweak>]]]]``. +If no ``VERSION`` is given, the ``PROJECT_VERSION`` variable is used. +If this hasn’t been set, it errors out. The ``VERSION`` argument is also used +to replace the ``@PACKAGE_VERSION@`` string in the configuration file. + +``COMPATIBILITY`` shall be any of the options accepted by the +:cmake:command:`write_basic_package_version_file` command +(``AnyNewerVersion``, ``SameMajorVersion``, ``SameMinorVersion`` [CMake 3.11], +or ``ExactVersion``). +These options are explained in :cmake:command:`write_basic_package_version_file` +command documentation. +If your project has more elaborate version matching rules, you will need to +write your own custom ConfigVersion.cmake file instead of using this macro. + +The ``<Name>Config.cmake`` file is generated using +:cmake:command:`configure_package_config_file`. The +``NO_SET_AND_CHECK_MACRO``, ``NO_CHECK_REQUIRED_COMPONENTS_MACRO``, and +arguments are passed to this function. + +By default :command:`install_basic_package_files` also generates the two helper +macros ``set_and_check()`` and ``check_required_components()`` into the +``<Name>Config.cmake`` file. ``set_and_check()`` should be used instead of the +normal :cmake:command:`set()` command for setting directories and file locations. +Additionally to setting the variable it also checks that the referenced file +or directory actually exists and fails with a ``FATAL_ERROR`` otherwise. +This makes sure that the created ``<Name>Config.cmake`` file does not contain +wrong references. +When using the ``NO_SET_AND_CHECK_MACRO, this macro is not generated into the +``<Name>Config.cmake`` file. + +By default, :command:`install_basic_package_files` append a call to +``check_required_components(<Name>)`` in ``<Name>Config.cmake`` file if the +package supports components. This macro checks whether all requested, +non-optional components have been found, and if this is not the case, sets the +``<Name>_FOUND`` variable to ``FALSE``, so that the package is considered to +be not found. It does that by testing the ``<Name>_<Component>_FOUND`` +variables for all requested required components. When using the +``NO_CHECK_REQUIRED_COMPONENTS_MACRO`` option, this macro is not generated +into the ``<Name>Config.cmake`` file. + +Finally, the files in the build and install directory are exactly the same. + +See the documentation of :module:`CMakePackageConfigHelpers` module for +further information and references therein. + +If the ``CONFIG_TEMPLATE`` argument is passed, the specified file +is used as template for generating the configuration file, otherwise +this module expects to find a ``<Name>Config.cmake.in`` or +``<name>-config.cmake.in`` file either in current source directory. +If the file does not exist, a very basic file is created. + +A set of variables are checked and passed to +:cmake:command:`configure_package_config_file` as ``PATH_VARS``. For each of the +``SUFFIX`` considered, if one of the variables:: + + <VARS_PREFIX>_(BUILD|INSTALL)_<SUFFIX> + (BUILD|INSTALL)_<VARS_PREFIX>_<SUFFIX> + +is defined, the ``<VARS_PREFIX>_<SUFFIX>`` variable will be defined +before configuring the package. In order to use that variable in the +config file, you have to add a line:: + + set_and_check(<VARS_PREFIX>_<SUFFIX> \"@PACKAGE_<VARS_PREFIX>_<SUFFIX>@\") + +if the path must exist or just:: + + set(<VARS_PREFIX>_<SUFFIX> \"@PACKAGE_<VARS_PREFIX>_<SUFFIX>@\") + +if the path could be missing. + +These variable will have different values whether you are using the +package from the build tree or from the install directory. Also these +files will contain only relative paths, meaning that you can move the +whole installation and the CMake files will still work. + +Default ``PATH_VARS`` suffixes are:: + + BINDIR BIN_DIR + SBINDIR SBIN_DIR + LIBEXECDIR LIBEXEC_DIR + SYSCONFDIR SYSCONF_DIR + SHAREDSTATEDIR SHAREDSTATE_DIR + LOCALSTATEDIR LOCALSTATE_DIR + LIBDIR LIB_DIR + INCLUDEDIR INCLUDE_DIR + OLDINCLUDEDIR OLDINCLUDE_DIR + DATAROOTDIR DATAROOT_DIR + DATADIR DATA_DIR + INFODIR INFO_DIR + LOCALEDIR LOCALE_DIR + MANDIR MAN_DIR + DOCDIR DOC_DIR + +more suffixes can be added using the ``EXTRA_PATH_VARS_SUFFIX`` +argument. + + +The ``<Name>Targets.cmake`` is generated using :cmake:command:`export(EXPORT)` +in the build tree and :cmake:command:`install(EXPORT)` in the installation +directory. The targets are exported using the value for the ``NAMESPACE`` +argument as namespace. +The export can be passed using the ``EXPORT`` argument. If no export is +used (e.g. for a CMake script library), pass ``NO_EXPORT``. + +If the ``INCLUDE_FILE`` argument is passed, the content of the specified file +(which might contain ``@variables@``) is appended to the generated +``<Name>Config.cmake`` file. +If the ``INCLUDE_CONTENT`` argument is passed, the specified content +(which might contain ``@variables@``) is appended to the generated +``<Name>Config.cmake`` file. +When a ``CONFIG_TEMPLATE`` is passed, or a ``<Name>ConfigVersion.cmake.in`` or +a ``<name>-config-version.cmake.in file is available, these 2 arguments are +used to replace the ``@INCLUDED_CONTENT@`` string in this file. +This allows one to inject custom code to this file, useful e.g. to set +additional variables which are loaded by downstream projects. + +Note that content specified with ``INCLUDE_FILE`` or ``INCLUDE_CONTENT`` +cannot reference any of the ``PATH_VARS`` because this content is not +expanded by :cmake:command:`configure_package_config_file`. + +If the ``COMPONENT`` argument is passed, it is forwarded to the +:cmake:command:`install` commands, otherwise ``<Name>`` is used. +#]=======================================================================] + + +if(COMMAND install_basic_package_files) + return() +endif() + + +include(GNUInstallDirs) +include(CMakePackageConfigHelpers) +include(CMakeParseArguments) + + +function(INSTALL_BASIC_PACKAGE_FILES _Name) + + set(_options ARCH_INDEPENDENT + NO_EXPORT + NO_SET_AND_CHECK_MACRO + NO_CHECK_REQUIRED_COMPONENTS_MACRO + UPPERCASE_FILENAMES + LOWERCASE_FILENAMES + NO_COMPATIBILITY_VARS # Deprecated + ENABLE_COMPATIBILITY_VARS) # Deprecated + set(_oneValueArgs VERSION + COMPATIBILITY + EXPORT + FIRST_TARGET # Deprecated + TARGETS_PROPERTY # Deprecated + VARS_PREFIX + EXPORT_DESTINATION + INSTALL_DESTINATION + DESTINATION # Deprecated + NAMESPACE + CONFIG_TEMPLATE + INCLUDE_FILE + INCLUDE_CONTENT + COMPONENT) + set(_multiValueArgs EXTRA_PATH_VARS_SUFFIX + TARGETS # Deprecated + TARGETS_PROPERTIES # Deprecated + DEPENDENCIES + PRIVATE_DEPENDENCIES) + cmake_parse_arguments(_IBPF "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" "${ARGN}") + + if(NOT DEFINED _IBPF_VARS_PREFIX) + set(_IBPF_VARS_PREFIX ${_Name}) + endif() + + if(NOT DEFINED _IBPF_VERSION) + if(NOT DEFINED PROJECT_VERSION) + message(FATAL_ERROR "VERSION argument is required (PROJECT_VERSION is not defined)") + endif() + set(_IBPF_VERSION ${PROJECT_VERSION}) + endif() + + if(NOT DEFINED _IBPF_COMPATIBILITY) + message(FATAL_ERROR "COMPATIBILITY argument is required") + endif() + + unset(_arch_independent) + if(_IBPF_ARCH_INDEPENDENT) + set(_arch_independent ARCH_INDEPENDENT) + endif() + + if(_IBPF_UPPERCASE_FILENAMES AND _IBPF_LOWERCASE_FILENAMES) + message(FATAL_ERROR "UPPERCASE_FILENAMES and LOWERCASE_FILENAMES arguments cannot be used together") + endif() + + if(DEFINED _IBPF_INCLUDE_FILE AND DEFINED _IBPF_INCLUDE_CONTENT) + message(FATAL_ERROR "INCLUDE_FILE and INCLUDE_CONTENT arguments cannot be used together") + endif() + + # Prepare install and export commands + unset(_targets) + set(_install_cmd EXPORT ${_Name}) + set(_export_cmd EXPORT ${_Name}) + + if(DEFINED _IBPF_EXPORT) + if(_IBPF_NO_EXPORT OR DEFINED _IBPF_TARGETS OR DEFINED _IBPF_TARGETS_PROPERTIES OR DEFINED _IBPF_TARGETS_PROPERTIES) + message(FATAL_ERROR "EXPORT cannot be used with NO_EXPORT, TARGETS, TARGETS_PROPERTY, or TARGETS_PROPERTIES") + endif() + + set(_export_cmd EXPORT ${_IBPF_EXPORT}) + set(_install_cmd EXPORT ${_IBPF_EXPORT}) + + elseif(_IBPF_NO_EXPORT) + if(DEFINED _IBPF_TARGETS OR DEFINED _IBPF_TARGETS_PROPERTIES OR DEFINED _IBPF_TARGETS_PROPERTIES) + message(FATAL_ERROR "NO_EXPORT cannot be used with TARGETS, TARGETS_PROPERTY, or TARGETS_PROPERTIES") + endif() + + elseif(DEFINED _IBPF_TARGETS) + message(DEPRECATION "TARGETS is deprecated. Use EXPORT instead") + + if(DEFINED _IBPF_TARGETS_PROPERTY OR DEFINED _IBPF_TARGETS_PROPERTIES) + message(FATAL_ERROR "TARGETS cannot be used with TARGETS_PROPERTY or TARGETS_PROPERTIES") + endif() + + set(_targets ${_IBPF_TARGETS}) + set(_export_cmd TARGETS ${_IBPF_TARGETS}) + + elseif(DEFINED _IBPF_TARGETS_PROPERTY) + message(DEPRECATION "TARGETS_PROPERTY is deprecated. Use EXPORT instead") + + if(DEFINED _IBPF_TARGETS_PROPERTIES) + message(FATAL_ERROR "TARGETS_PROPERTIES cannot be used with TARGETS_PROPERTIES") + endif() + + get_property(_targets GLOBAL PROPERTY ${_IBPF_TARGETS_PROPERTY}) + set(_export_cmd TARGETS ${_targets}) + + elseif(DEFINED _IBPF_TARGETS_PROPERTIES) + message(DEPRECATION "TARGETS_PROPERTIES is deprecated. Use EXPORT instead") + + set(_targets "") # Defined but empty + foreach(_prop ${_IBPF_TARGETS_PROPERTIES}) + get_property(_prop_val GLOBAL PROPERTY ${_prop}) + list(APPEND _targets ${_prop_val}) + endforeach() + set(_export_cmd TARGETS ${_targets}) + + endif() + + # Path for installed cmake files + if(DEFINED _IBPF_DESTINATION) + message(DEPRECATION "DESTINATION is deprecated. Use INSTALL_DESTINATION instead") + if(NOT DEFINED _IBPF_INSTALL_DESTINATION) + set(_IBPF_INSTALL_DESTINATION ${_IBPF_DESTINATION}) + endif() + endif() + + # If not set by the user, choose an adequate destination + if(NOT DEFINED _IBPF_INSTALL_DESTINATION) + if(_IBPF_ARCH_INDEPENDENT) + set(_IBPF_INSTALL_DESTINATION ${CMAKE_INSTALL_DATADIR}/cmake/${_Name}) + else() + set(_IBPF_INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${_Name}) + endif() + endif() + + # FIRST_TARGET is no longer used + if(DEFINED _IBPF_FIRST_TARGET) + message(DEPRECATION "FIRST_TARGET is deprecated.") + endif() + + # NO_COMPATIBILITY_VARS and ENABLE_COMPATIBILITY_VARS cannot be used together + if(_IBPF_NO_COMPATIBILITY_VARS AND _ENABLE_COMPATIBILITY_VARS) + message(FATAL_ERROR "NO_COMPATIBILITY_VARS and ENABLE_COMPATIBILITY_VARS cannot be used together") + endif() + # NO_COMPATIBILITY_VARS is deprecated + if(_IBPF_NO_COMPATIBILITY_VARS) + message(DEPRECATION "NO_COMPATIBILITY_VARS is deprecated.") + endif() + # ENABLE_COMPATIBILITY_VARS is deprecated + if(_IBPF_ENABLE_COMPATIBILITY_VARS) + message(DEPRECATION "ENABLE_COMPATIBILITY_VARS is deprecated.") + endif() + # ENABLE_COMPATIBILITY_VARS does not work with EXPORT + if(NOT DEFINED _targets AND _IBPF_ENABLE_COMPATIBILITY_VARS) + message(FATAL_ERROR "ENABLE_COMPATIBILITY_VARS does not work with EXPORT") + endif() + # ENABLE_COMPATIBILITY_VARS can be enabled for projects still using targets + if(DEFINED _targets AND NOT _IBPF_NO_COMPATIBILITY_VARS AND NOT _IBPF_ENABLE_COMPATIBILITY_VARS) + message(DEPRECATION "Compatibility variables are no longer generated. Use ENABLE_COMPATIBILITY_VARS to re-enable them (deprecated) or define them using either INCLUDE_FILE or INCLUDE_CONTENT (recommended).") + endif() + + if(NOT DEFINED _IBPF_EXPORT_DESTINATION) + set(_IBPF_EXPORT_DESTINATION "${CMAKE_BINARY_DIR}") + elseif(NOT IS_ABSOLUTE "${_IBPF_EXPORT_DESTINATION}") + set(_IBPF_EXPORT_DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/${_IBPF_EXPORT_DESTINATION}") + endif() + + if(NOT DEFINED _IBPF_NAMESPACE) + set(_IBPF_NAMESPACE "${_Name}::") + endif() + + if(NOT DEFINED _IBPF_COMPONENT) + set(_IBPF_COMPONENT "${_Name}") + endif() + + if(_IBPF_NO_SET_AND_CHECK_MACRO) + list(APPEND configure_package_config_file_extra_args NO_SET_AND_CHECK_MACRO) + endif() + + if(_IBPF_NO_CHECK_REQUIRED_COMPONENTS_MACRO) + list(APPEND configure_package_config_file_extra_args NO_CHECK_REQUIRED_COMPONENTS_MACRO) + endif() + + + + # Set input file for config, and ensure that _IBPF_UPPERCASE_FILENAMES + # and _IBPF_LOWERCASE_FILENAMES are set correctly + unset(_config_cmake_in) + set(_generate_file 0) + if(DEFINED _IBPF_CONFIG_TEMPLATE) + if(NOT EXISTS "${_IBPF_CONFIG_TEMPLATE}") + message(FATAL_ERROR "Config template file \"${_IBPF_CONFIG_TEMPLATE}\" not found") + endif() + set(_config_cmake_in "${_IBPF_CONFIG_TEMPLATE}") + if(NOT _IBPF_UPPERCASE_FILENAMES AND NOT _IBPF_LOWERCASE_FILENAMES) + if("${_IBPF_CONFIG_TEMPLATE}" MATCHES "${_Name}Config.cmake.in") + set(_IBPF_UPPERCASE_FILENAMES 1) + elseif("${_IBPF_CONFIG_TEMPLATE}" MATCHES "${_name}-config.cmake.in") + set(_IBPF_LOWERCASE_FILENAMES 1) + else() + set(_IBPF_UPPERCASE_FILENAMES 1) + endif() + endif() + else() + string(TOLOWER "${_Name}" _name) + if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${_Name}Config.cmake.in") + set(_config_cmake_in "${CMAKE_CURRENT_SOURCE_DIR}/${_Name}Config.cmake.in") + if(NOT _IBPF_UPPERCASE_FILENAMES AND NOT _IBPF_LOWERCASE_FILENAMES) + set(_IBPF_UPPERCASE_FILENAMES 1) + endif() + elseif(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${_name}-config.cmake.in") + set(_config_cmake_in "${CMAKE_CURRENT_SOURCE_DIR}/${_name}-config.cmake.in") + if(NOT _IBPF_UPPERCASE_FILENAMES AND NOT _IBPF_LOWERCASE_FILENAMES) + set(_IBPF_LOWERCASE_FILENAMES 1) + endif() + else() + set(_generate_file 1) + if(_IBPF_LOWERCASE_FILENAMES) + set(_config_cmake_in "${CMAKE_CURRENT_BINARY_DIR}/${_name}-config.cmake.in") + else() + set(_config_cmake_in "${CMAKE_CURRENT_BINARY_DIR}/${_Name}Config.cmake.in") + set(_IBPF_UPPERCASE_FILENAMES 1) + endif() + endif() + endif() + + # Set input file containing user variables + if(DEFINED _IBPF_INCLUDE_FILE) + if(NOT IS_ABSOLUTE "${_IBPF_INCLUDE_FILE}") + if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${_IBPF_INCLUDE_FILE}") + set(_IBPF_INCLUDE_FILE "${CMAKE_CURRENT_SOURCE_DIR}/${_IBPF_INCLUDE_FILE}") + endif() + endif() + if(NOT EXISTS "${_IBPF_INCLUDE_FILE}") + message(FATAL_ERROR "File \"${_IBPF_INCLUDE_FILE}\" not found") + endif() + file(READ ${_IBPF_INCLUDE_FILE} _IBPF_INCLUDE_CONTENT) + endif() + + if(DEFINED _IBPF_INCLUDE_CONTENT) + string(CONFIGURE ${_IBPF_INCLUDE_CONTENT} + _IBPF_INCLUDE_CONTENT + @ONLY) + set(INCLUDED_CONTENT +"#### Expanded from INCLUDE_FILE/INCLUDE_CONTENT by install_basic_package_files() #### + +${_IBPF_INCLUDE_CONTENT} + +##################################################################################### +") + endif() + + # Backwards compatibility + if(NOT _generate_file AND DEFINED _IBPF_INCLUDE_FILE) + file(READ ${_config_cmake_in} _config_cmake_in_content) + if("${_config_cmake_in_content}" MATCHES "@INCLUDED_FILE_CONTENT@") + message(DEPRECATION "The @INCLUDED_FILE_CONTENT@ variable is deprecated in favour of @INCLUDED_CONTENT@") + set(INCLUDED_FILE_CONTENT "${INCLUDED_CONTENT}") + endif() + endif() + + # Select output file names + if(_IBPF_UPPERCASE_FILENAMES) + set(_config_filename ${_Name}Config.cmake) + set(_version_filename ${_Name}ConfigVersion.cmake) + set(_targets_filename ${_Name}Targets.cmake) + elseif(_IBPF_LOWERCASE_FILENAMES) + set(_config_filename ${_name}-config.cmake) + set(_version_filename ${_name}-config-version.cmake) + set(_targets_filename ${_name}-targets.cmake) + endif() + + + # If the template config file does not exist, write a basic one + if(_generate_file) + # Generate the compatibility code + unset(_compatibility_vars) + if(_IBPF_ENABLE_COMPATIBILITY_VARS) + unset(_get_include_dir_code) + unset(_set_include_dir_code) + unset(_target_list) + foreach(_target ${_targets}) + list(APPEND _target_list ${_IBPF_NAMESPACE}${_target}) + endforeach() + if(DEFINED ${_IBPF_VARS_PREFIX}_BUILD_INCLUDEDIR OR + DEFINED BUILD_${_IBPF_VARS_PREFIX}_INCLUDEDIR OR + DEFINED ${_IBPF_VARS_PREFIX}_INSTALL_INCLUDEDIR OR + DEFINED INSTALL_${_IBPF_VARS_PREFIX}_INCLUDEDIR) + list(APPEND _include_dir_list "\"\@PACKAGE_${_IBPF_VARS_PREFIX}_INCLUDEDIR\@\"") + elseif(DEFINED ${_IBPF_VARS_PREFIX}_BUILD_INCLUDE_DIR OR + DEFINED BUILD_${_IBPF_VARS_PREFIX}_INCLUDE_DIR OR + DEFINED ${_IBPF_VARS_PREFIX}_INSTALL_INCLUDE_DIR OR + DEFINED INSTALL_${_IBPF_VARS_PREFIX}_INCLUDE_DIR) + list(APPEND _include_dir_list "\"\@PACKAGE_${_IBPF_VARS_PREFIX}_INCLUDE_DIR\@\"") + else() + unset(_include_dir_list) + foreach(_target ${_targets}) + list(APPEND _include_dir_list "\$<TARGET_PROPERTY:${_IBPF_NAMESPACE}${_target},INTERFACE_INCLUDE_DIRECTORIES>") + endforeach() + string(REPLACE ";" " " _include_dir_list "${_include_dir_list}") + string(REPLACE ";" " " _target_list "${_target_list}") + set(_set_include_dir "") + endif() + set(_compatibility_vars +"# Compatibility\nset(${_Name}_LIBRARIES ${_target_list}) +set(${_Name}_INCLUDE_DIRS ${_include_dir_list}) +if(NOT \"\${${_Name}_INCLUDE_DIRS}\" STREQUAL \"\") + list(REMOVE_DUPLICATES ${_Name}_INCLUDE_DIRS) +endif() +") + endif() + + if(_IBPF_NO_EXPORT) + set(_include_targets_cmd "") + else() + set(_include_targets_cmd "include(\"\${CMAKE_CURRENT_LIST_DIR}/${_targets_filename}\")") + endif() + + # Write the file + file(WRITE "${_config_cmake_in}" +"set(${_IBPF_VARS_PREFIX}_VERSION \@PACKAGE_VERSION\@) + +\@PACKAGE_INIT\@ + +\@PACKAGE_DEPENDENCIES\@ + +${_include_targets_cmd} + +${_compatibility_vars} + +\@INCLUDED_CONTENT\@ +") + endif() + + # Make relative paths absolute (needed later on) and append the + # defined variables to _(build|install)_path_vars_suffix + foreach(p BINDIR BIN_DIR + SBINDIR SBIN_DIR + LIBEXECDIR LIBEXEC_DIR + SYSCONFDIR SYSCONF_DIR + SHAREDSTATEDIR SHAREDSTATE_DIR + LOCALSTATEDIR LOCALSTATE_DIR + LIBDIR LIB_DIR + INCLUDEDIR INCLUDE_DIR + OLDINCLUDEDIR OLDINCLUDE_DIR + DATAROOTDIR DATAROOT_DIR + DATADIR DATA_DIR + INFODIR INFO_DIR + LOCALEDIR LOCALE_DIR + MANDIR MAN_DIR + DOCDIR DOC_DIR + ${_IBPF_EXTRA_PATH_VARS_SUFFIX}) + if(DEFINED ${_IBPF_VARS_PREFIX}_BUILD_${p}) + list(APPEND _build_path_vars_suffix ${p}) + list(APPEND _build_path_vars "${_IBPF_VARS_PREFIX}_${p}") + endif() + if(DEFINED BUILD_${_IBPF_VARS_PREFIX}_${p}) + list(APPEND _build_path_vars_suffix ${p}) + list(APPEND _build_path_vars "${_IBPF_VARS_PREFIX}_${p}") + endif() + if(DEFINED ${_IBPF_VARS_PREFIX}_INSTALL_${p}) + list(APPEND _install_path_vars_suffix ${p}) + list(APPEND _install_path_vars "${_IBPF_VARS_PREFIX}_${p}") + endif() + if(DEFINED INSTALL_${_IBPF_VARS_PREFIX}_${p}) + list(APPEND _install_path_vars_suffix ${p}) + list(APPEND _install_path_vars "${_IBPF_VARS_PREFIX}_${p}") + endif() + endforeach() + + + # <Name>ConfigVersion.cmake file (same for build tree and intall) + write_basic_package_version_file("${_IBPF_EXPORT_DESTINATION}/${_version_filename}" + VERSION ${_IBPF_VERSION} + COMPATIBILITY ${_IBPF_COMPATIBILITY} + ${_arch_independent}) + install(FILES "${_IBPF_EXPORT_DESTINATION}/${_version_filename}" + DESTINATION ${_IBPF_INSTALL_DESTINATION} + COMPONENT ${_IBPF_COMPONENT}) + + + # Prepare PACKAGE_DEPENDENCIES variable + set(_need_private_deps 0) + if(NOT BUILD_SHARED_LIBS) + set(_need_private_deps 1) + endif() + + unset(PACKAGE_DEPENDENCIES) + if(DEFINED _IBPF_DEPENDENCIES OR (DEFINED _IBPF_PRIVATE_DEPENDENCIES AND _need_private_deps)) + set(PACKAGE_DEPENDENCIES "#### Expanded from @PACKAGE_DEPENDENCIES@ by install_basic_package_files() ####\n\ninclude(CMakeFindDependencyMacro)\n") + + foreach(_dep ${_IBPF_DEPENDENCIES}) + string(APPEND PACKAGE_DEPENDENCIES "find_dependency(${_dep})\n") + endforeach() + + if(_need_private_deps) + foreach(_dep ${_IBPF_PRIVATE_DEPENDENCIES}) + string(APPEND PACKAGE_DEPENDENCIES "find_dependency(${_dep})\n") + endforeach() + endif() + + string(APPEND PACKAGE_DEPENDENCIES "\n###############################################################################\n") + endif() + + # Prepare PACKAGE_VERSION variable + set(PACKAGE_VERSION ${_IBPF_VERSION}) + + # <Name>Config.cmake (build tree) + foreach(p ${_build_path_vars_suffix}) + if(DEFINED ${_IBPF_VARS_PREFIX}_BUILD_${p}) + set(${_IBPF_VARS_PREFIX}_${p} "${${_IBPF_VARS_PREFIX}_BUILD_${p}}") + elseif(DEFINED BUILD_${_IBPF_VARS_PREFIX}_${p}) + set(${_IBPF_VARS_PREFIX}_${p} "${BUILD_${_IBPF_VARS_PREFIX}_${p}}") + endif() + endforeach() + configure_package_config_file("${_config_cmake_in}" + "${_IBPF_EXPORT_DESTINATION}/${_config_filename}" + INSTALL_DESTINATION ${_IBPF_EXPORT_DESTINATION} + PATH_VARS ${_build_path_vars} + ${configure_package_config_file_extra_args} + INSTALL_PREFIX ${CMAKE_BINARY_DIR}) + + # <Name>Config.cmake (installed) + foreach(p ${_install_path_vars_suffix}) + if(DEFINED ${_IBPF_VARS_PREFIX}_INSTALL_${p}) + set(${_IBPF_VARS_PREFIX}_${p} "${${_IBPF_VARS_PREFIX}_INSTALL_${p}}") + elseif(DEFINED INSTALL_${_IBPF_VARS_PREFIX}_${p}) + set(${_IBPF_VARS_PREFIX}_${p} "${INSTALL_${_IBPF_VARS_PREFIX}_${p}}") + endif() + endforeach() + configure_package_config_file("${_config_cmake_in}" + "${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${_config_filename}.install" + INSTALL_DESTINATION ${_IBPF_INSTALL_DESTINATION} + PATH_VARS ${_install_path_vars} + ${configure_package_config_file_extra_args}) + install(FILES "${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${_config_filename}.install" + DESTINATION ${_IBPF_INSTALL_DESTINATION} + RENAME ${_config_filename} + COMPONENT ${_IBPF_COMPONENT}) + + + # <Name>Targets.cmake (build tree) + if(NOT _IBPF_NO_EXPORT) + export(${_export_cmd} + NAMESPACE ${_IBPF_NAMESPACE} + FILE "${_IBPF_EXPORT_DESTINATION}/${_targets_filename}") + endif() + + # Export build directory if CMAKE_EXPORT_PACKAGE_REGISTRY is set. + # CMake >= 3.15 already checks for CMAKE_EXPORT_PACKAGE_REGISTRY in `export(PACKAGE)` (cf. + # cf. https://cmake.org/cmake/help/latest/policy/CMP0090.html), and we effectively back-port + # this behavior to earlier versions. + # Note that even never CMake versions may apply old policy behaviors if the consuming project + # requires a lower version of CMake (e.g. `cmake_minimum_required(VERSION 3.14)`), so the + # check for `CMAKE_EXPORT_PACKAGE_REGISTRY` is necessary for CMake >= 3.15 as well. + if(CMAKE_EXPORT_PACKAGE_REGISTRY) + export(PACKAGE ${_Name}) + endif() + + # <Name>Targets.cmake (installed) + if(NOT _IBPF_NO_EXPORT) + install(${_install_cmd} + NAMESPACE ${_IBPF_NAMESPACE} + DESTINATION ${_IBPF_INSTALL_DESTINATION} + FILE "${_targets_filename}" + COMPONENT ${_IBPF_COMPONENT}) + endif() +endfunction() diff --git a/thirdparty/gsl-lite/doc/Reference.md b/thirdparty/gsl-lite/doc/Reference.md new file mode 100644 index 000000000..f182e9783 --- /dev/null +++ b/thirdparty/gsl-lite/doc/Reference.md @@ -0,0 +1,1389 @@ +# Reference documentation + +## Contents + +- [Contract and assertion checks](#contract-and-assertion-checks): `gsl_Expects( pred )`, `gsl_Ensures( pred )`, `gsl_Assert( pred )`, and more +- [Pointer annotations](#pointer-annotations): `owner<P>`, `not_null<P>`, and `not_null_ic<P>` +- [Numeric type conversions](#numeric-type-conversions): `narrow<T>( u )`, `narrow_failfast<T>( u )`, and `narrow_cast<T>( u )` +- [Safe contiguous ranges](#safe-contiguous-ranges): `span<T, Extent>` +- [Bounds-checked element access](#bounds-checked-element-access): `at( container, index )` +- [Integer type aliases](#integer-type-aliases): `index`, `dim`, `stride`, `diff` +- [String type aliases](#string-type-aliases): `zstring`, `czstring`, `wzstring`, `cwzstring` +- [Ad hoc resource management (C++11 and higher)](#ad-hoc-resource-management-c11-and-higher): `finally( action )`, `on_return( action )`, and `on_error( action )` +- [Feature checking macros](#feature-checking-macros) +- [Polyfills](#polyfills) +- [Configuration options and switches](#configuration-options-and-switches) +- [Configuration changes, deprecated and removed features](#configuration-changes-deprecated-and-removed-features) + + +## Contract and assertion checks + +(Core Guidelines reference: [GSL.assert: Assertions](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#SS-assertions)) + +There are several macros for expressing preconditions, postconditions, and invariants: + +- `gsl_FailFast()` to indicate unreachable code +- `gsl_Expects( cond )` for simple preconditions +- `gsl_Ensures( cond )` for simple postconditions +- `gsl_Assert( cond )` for simple assertions +- `gsl_ExpectsDebug( cond )` for debug-mode preconditions +- `gsl_EnsuresDebug( cond )` for debug-mode postconditions +- `gsl_AssertDebug( cond )` for debug-mode assertions +- `gsl_ExpectsAudit( cond )` for preconditions that are expensive or include potentially opaque function calls +- `gsl_EnsuresAudit( cond )` for postconditions that are expensive or include potentially opaque function calls +- `gsl_AssertAudit( cond )` for assertions that are expensive or include potentially opaque function calls + +**Example:** +```c++ +template< class RandomIt > +auto median( RandomIt first, RandomIt last ) +{ + gsl_Expects( first != last ); + + // Verifying that a range of elements is sorted is an expensive operation that changes the + // computational complexity of the function `median()` from 𝒪(1) to 𝒪(n). Therefore, we + // express it as an audit-level contract check. + gsl_ExpectsAudit( std::is_sorted( first, last ) ); + + auto count = last - first; + return count % 2 != 0 + ? first[ count / 2 ] + : std::midpoint( first[ count / 2 ], first[ count / 2 + 1 ] ); +} +``` + +The behavior of the different flavors of pre-/postcondition checks and assertions depends on a number of [configuration macros](#contract-checking-configuration-macros): + +- The macros **`gsl_Expects()`**, **`gsl_Ensures()`**, and **`gsl_Assert()`** are compiled to runtime checks unless contract + checking is disabled with the `gsl_CONFIG_CONTRACT_CHECKING_OFF` configuration macro. + +- Contract checks expressed with **`gsl_ExpectsAudit()`**, **`gsl_EnsuresAudit()`**, and **`gsl_AssertAudit()`** are discarded by + default. In order to have them checked at runtime, the `gsl_CONFIG_CONTRACT_CHECKING_AUDIT` configuration macro must be defined. + +- The macros **`gsl_ExpectsDebug()`**, **`gsl_EnsuresDebug()`**, and **`gsl_AssertDebug()`** are compiled to runtime checks unless + contract checking is disabled by defining `gsl_CONFIG_CONTRACT_CHECKING_OFF` or assertions are disabled by defining `NDEBUG`. + They can be used in place of the [`assert()`](https://en.cppreference.com/w/cpp/error/assert) macro from the C standard library. + (Note that defining `gsl_CONFIG_CONTRACT_CHECKING_AUDIT` also enables checking of the `gsl_*Debug()` macros regardless of + whether `NDEBUG` is defined.) + +- The **`gsl_Expects*()`**, **`gsl_Ensures*()`**, **`gsl_Assert*()`** categories of checks can be disabled individually with the + `gsl_CONFIG_CONTRACT_CHECKING_EXPECTS_OFF`, `gsl_CONFIG_CONTRACT_CHECKING_ENSURES_OFF`, or `gsl_CONFIG_CONTRACT_CHECKING_ASSERT_OFF` + configuration macros. + +- **`gsl_FailFast()`** is similar to `gsl_Assert( false )` but is guaranteed to interrupt the current path of execution even + if contract checking is disabled with configuration macros. It is useful in places which should not be reachable during program + execution. For example: + ```c++ + enum class Color : int { red, green, blue }; + std::string colorToString( Color color ) + { + switch (color) + { + case Color::red: return "red"; + case Color::green: return "green"; + case Color::blue: return "blue"; + } + gsl_FailFast(); + } + ``` + The C++ language permits casting any representable integer value to an enum. Therefore, `colorToString(Color(0xFF00FF))` + is legal C++, but not actually supported by this `colorToString()` implementation. `gsl_FailFast()` is employed here to ensure + that passing unsupported values to `colorToString()` will be detected at runtime. + + `gsl_FailFast()` behaves as if annotated by the [`[[noreturn]]`](https://en.cppreference.com/w/cpp/language/attributes/noreturn) + attribute. A C++11 compiler will therefore not emit a warning about a missing return statement in `colorToString()`. + <!--(Unrelated note: the `switch` statement above deliberately elides the `default:` clause. Because the switch statement is wrapped + in a dedicated function, we can use `return` instead of `break` to conclude the `case` clauses, and hence the default handler + can simply go after the `switch` statement. The benefit of avoiding the `default:` clause is that most compilers will understand + that the `switch` statement is supposed to handle all defined enumeration values and thus issue a warning if the programmer adds + a new enumeration value (say, `Color::yellow`) but forgets to amend the `switch` statement.)--> + + +## Pointer annotations + +- [`owner<P>` (C++11 and higher)](#ownerp-c11-and-higher) +- [`not_null<P>`](#not_nullp) + - [Motivation](#motivation) + - [Reference](#reference) + - [Nullability and the moved-from state](#nullability-and-the-moved-from-state) +- [`not_null_ic<P>`](#not_null_icp) + +(Core Guidelines reference: [GSL.view: Views](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#gslview-views)) + +*gsl-lite* defines the three pointer type annotations `owner<P>`, `not_null<P>`, and `not_null_ic<P>` which let the user signify additional intent: + +- `owner<P>` indicates that a raw pointer `P` carries ownership of the object it points to, and is thus responsible for managing its lifetime. +- `not_null<P>` and `not_null_ic<P>` indicate that a pointer `P` must not be `nullptr`. + +### `owner<P>` (C++11 and higher) + +`gsl_lite::owner<P>` is a type alias that solely serves the purpose of expressing intent: +```c++ +template< class P > +requires ( std::is_pointer_v<P> ) +using owner = P; +``` +(*Note:* The actual definition uses a SFINAE constraint to support C\+\+11 to C\+\+17). + +As far as the type system and the runtime behavior is concerned, `owner<P>` is exactly equivalent to `P`. However, the annotation conveys +intent to a reader, and static analysis tools may use the annotation to impose semantic checks based on the assumption of ownership. + +If possible, a smart pointer with automatic lifetime management such as [`std::unique_ptr<>`](https://en.cppreference.com/w/cpp/memory/unique_ptr) +or [`std::shared_ptr<>`](https://en.cppreference.com/w/cpp/memory/shared_ptr) should be used instead. The purpose of `owner<>` is annotation of +raw pointers which cannot currently be replaced with a smart pointer. + + +### `not_null<P>` + +`gsl_lite::not_null<P>` is a class template that wraps a pointer type `P` while enforcing non-nullability. + +`not_null<P>` has no default constructor, and its unary constructors use [`gsl_Expects()`](#contract-and-assertion-checks) to check +that their argument is not `nullptr`. Therefore, when attempting to construct a `not_null<P>` from a null pointer, a runtime contract violation is triggered: +```c++ +using gsl_lite::not_null; + +int i = 42; +int * pi = &i; +int * pn = nullptr; + + // compile error: no default constructor +//not_null<int *> n; + + // compile error: no implicit conversion +//not_null<int *> npi = pi; + + // explicit conversion: runtime null check +not_null<int *> npi = not_null( pi ); + + // compile error: no implicit conversion +//not_null<int *> nn = nullptr; + + // compile error: no explicit conversion +//not_null<int *> nn = not_null( nullptr ); + + // explicit conversion: runtime null check ⇒ runtime contract violation +not_null<int *> npn = not_null( pn ); +``` + +#### Motivation + +<!--C++ knows two kinds of indirections: pointers and references. A pointer can refer to a special value known as `nullptr`, +which indicates it does not point to any object, and can be subsequently reassigned. In contrast, references must always +refer to a valid object, and they can be assigned only once, as part of their initialization.--> + +When defining function signatures, it is customary to use pointers and references to indicate whether an object +reference is required or optional: +```c++ +void lock( Mutex & m ); // requires a valid object reference + +struct ListNode +{ + ListNode* prev; + ListNode* next; + int payload; +}; +bool tryRemove( ListNode * x ); // also accepts a `nullptr` +``` + +But this convention does not apply to every situation. For example, accepting a pointer argument can also emphasize the fact +that the object's memory address may be taken and stored, as in the case of a list or tree node. Storing the memory address +of a by-reference argument "feels" wrong, and may be flagged by static analyzers: +```c++ +void insertAfter( ListNode & x, ListNode & newNode ) +{ + newNode.prev = &x; // <-- Eww. + newNode.next = x.next; + x.next = &newNode; // <-- Eww. +} +``` +The function would be less awkward if it accepted pointers. + +To make sure a pointer argument is not `nullptr`, we can add a precondition check to the function: +```c++ +void insertAfter( ListNode * x, ListNode * newNode ) +{ + gsl_Expects( x != nullptr ); + gsl_Expects( newNode != nullptr ); + + newNode->prev = x; + newNode->next = x->next; + x->next = newNode; +} +``` + +Writing all the precondition checks against `nullptr` quickly becomes tedious. And unlike the contract checks once envisioned +for C++20, precondition checks expressed with `gsl_Expects()` are not part of the function signature, which therefore does +not convey that it cannot handle `nullptr` input. + +This is where `not_null<>` comes in. With `not_null<>`, the precondition can be "lifted" into the type system, +and thus into the function signature: + +```c++ +void insertAfter( not_null<ListNode *> x, not_null<ListNode *> newNode ) +{ + newNode->prev = x; + newNode->next = x->next; + x->next = newNode; +} +``` + +All `not_null<>` constructors check their arguments for `nullptr` with `gsl_Expects()`, so the functions above can already assume +that their arguments will never be `nullptr`, and the explicit precondition checks can be omitted. + +When calling the function `insertAfter()`, it is understood that the caller passes ownership of the node `newNode`. +Transfer of ownership is best expressed with a smart pointer such as `std::unique_ptr<>`, which can also be used as an +argument to `not_null<>`: + +```c++ +void insertAfter( not_null<ListNode *> x, not_null<std::unique_ptr<ListNode>> newNode ); +``` + +A `not_null<std::unique_ptr<>>` can be passed around just like a `std::unique_ptr<>`: +```c++ +void insertAfterEnd( not_null<ListNode *> lastNode, not_null<std::unique_ptr<ListNode>> newNode ) +{ + gsl_Expects( lastNode->next == nullptr ); + + insertAfter( lastNode, std::move( newNode ) ); +} +``` + +Because `newNode` is non-nullable, releasing the pointer it holds is not straightforward: + +```c++ +void insertAfter( not_null<ListNode *> x, not_null<std::unique_ptr<ListNode>> newNode ) +{ + newNode->prev = x; + newNode->next = x->next; + x->next = newNode.release(); // error: `not_null<>` has no member function `release()` +} +``` + +To extract the raw pointer, we first have to extract a nullable `unique_ptr<>`: + +```c++ + std::unique_ptr<ListNode> rawNewNode = std::move( newNode ); + x->next = rawNewNode.release(); +``` + +This can be written as a one-liner with `gsl_lite::as_nullable()`: + +```c++ + x->next = gsl_lite::as_nullable( std::move( newNode ) ).release(); +``` + + +#### Reference + +`not_null<P>` strives to behave like the underlying type `P` as transparently as reasonably possible: + +- There is no runtime size overhead: `sizeof( not_null<P> ) == sizeof( P )`. +- `not_null<P>` implicitly converts to `Q` if `P` implicitly converts to `Q`. + For example, `not_null<int *>` implicitly converts to `int const *`. +- `not_null<P>` explicitly converts to `Q` if `P` explicitly converts to `Q`. +- `not_null<P>` can be dereferenced if `P` can be dereferenced. +- If `P` can be copied, `not_null<P>` can be copied. If `P` can be moved, `not_null<P>` can be moved. + For example, `not_null<T *>` is copyable, `not_null<std::unique_ptr<T>>` is movable but not copyable, and `not_null<std::shared_ptr<T>>` is copyable and movable. +- If `P` points to a `struct`, `class`, or `union`, `not_null<P>` defines the member access operator `operator->`. +- If `P` has a member function `P::get()`, `not_null<P>` also defines a member function `not_null<P>::get()` which forwards to `P::get()`. +- If `P` is a function pointer or a nullable function object such as [`std::function<>`](https://en.cppreference.com/w/cpp/utility/functional/function), + `not_null<>` defines the function call operator `operator()` which forwards the call to `P`: + ```c++ + long call( not_null<long (*)(long)> func, long arg ) + { + return func( arg ); + } + ``` +- `Q` implicitly converts to `not_null<P>` if `Q` is non-nullable and implicitly converts to `P`. + For example, [`std::labs`](https://en.cppreference.com/w/cpp/numeric/math/abs) implicitly converts to `not_null<long (*)(long)>`: + ```c++ + long callAbs( long val ) + { + return call( std::labs, val ); + } + ``` +- `Q` explicitly converts to `not_null<P>` if `Q` is nullable and implicitly converts to `P`, or if `Q` explicitly converts to `P`. + For example: + ```c++ + std::string readLine( not_null<std::FILE*> file ); + std::FILE* file = ...; + //readLine( file ); // does not compile: `file` is nullable + readLine( not_null( file ) ); // compiles and executes a check at runtime + ``` +- If `P` is hashable (that is, the [`std::hash<P>`](https://en.cppreference.com/w/cpp/utility/hash) specialization is *enabled*), `not_null<P>` is hashable. + +For C++14 and older, where [class template argument deduction](https://en.cppreference.com/w/cpp/language/class_template_argument_deduction) +is not available, *gsl-lite* defines a set of helper functions `make_not_null()` for explicitly constructing `not_null<>` objects. + +*gsl-lite* additionally defines the helper functions `make_unique<T>()` and `make_shared<T>()` which behave like +[`std::make_unique<T>()`](https://en.cppreference.com/w/cpp/memory/unique_ptr/make_unique) and +[`std::make_shared<T>()`](https://en.cppreference.com/w/cpp/memory/shared_ptr/make_shared) but return `not_null<std::unique_ptr<T>>` +and `not_null<std::shared_ptr<T>>`, respectively. + +`not_null<P>` is meant to point to single objects, not arrays of objects. It therefore does not define a subscript operator, +pointer increment or decrement operators, or pointer addition or subtraction operators, and +`gsl_lite::make_unique<T>()` and `gsl_lite::make_shared<T>()` are not defined for array types. + +To extract the nullable object wrapped by a `not_null<>` object, call `gsl_lite::as_nullable()`: +```c++ +auto npi = gsl_lite::make_unique<int>( 42 ); // not_null<std::unique_ptr<int>> +auto pi = gsl_lite::as_nullable( std::move( npi ) ); // std::unique_ptr<int> +``` + +This is useful when accessing operations of `P` not forwarded by `not_null<P>`: +```c++ +void insertAfter( not_null<ListNode *> x, not_null<std::unique_ptr<ListNode>> newNode ) +{ + newNode->prev = x; + newNode->next = x->next; + // no `not_null<>::release()` member function + x->next = gsl_lite::as_nullable( std::move( newNode ) ).release(); +} +``` + + +#### Nullability and the moved-from state + +Because `not_null<P>` retains the copyability and movability of `P`, a `not_null<P>` object may have a *moved-from state* if the +underlying pointer `P` has one. Therefore, a `not_null<P>` object may in fact be `nullptr` after it has been moved from: +```c++ +auto x = gsl_lite::make_unique<int>( 42 ); // not_null<std::unique_ptr<int>>() +auto y = std::move( x ); // x is now nullptr +*x = 43; // dereferencing a nullptr ⇒ runtime contract violation +``` +This is where *gsl-lite*'s implementation of `not_null<>` differs from the implementation of Microsoft GSL, which ensures that +its `not_null<P>` cannot ever become `nullptr`, rendering its `not_null<std::unique_ptr<T>>` immovable (cf. [microsoft/GSL#1022](https://github.com/microsoft/GSL/issues/1022)). +While this choice would prevent the error above, it inhibits many interesting use cases for `not_null<>`. +For example, consider the following resource handle class: + +```c++ +struct FileCloser +{ + void operator ()(std::FILE* file) const noexcept + { + std::fclose( file ); + } +}; +using FilePtr = std::unique_ptr<std::FILE, FileCloser>; + +class FileHandle +{ +private: + FilePtr file_; + +public: + FileHandle( FileHandle & rhs ) = default; + FileHandle & operator =( FileHandle & rhs ) = default; + + explicit FileHandle( FilePtr _file ) + : file_( std::move( _file ) ) + { + } + int getc() + { + return std::fgetc( file_.get() ); + } + ... +}; +``` + +To make `FileHandle` null-safe, we can add explicit precondition checks: + +```c++ +class FileHandle // movable +{ +private: + FilePtr file_; + +public: + FileHandle( FileHandle & rhs ) + : file_( std::move( rhs.file_ ) ) + { + gsl_Expects( file_ != nullptr ); + } + FileHandle & operator =( FileHandle & rhs ) + { + gsl_Expects( rhs.file_ != nullptr ); + file_ = std::move(rhs.file_); + return *this; + } + + explicit FileHandle( FilePtr _file ) + : file_( std::move( _file ) ) + { + gsl_Expects( file_ != nullptr ); + } + int getc() + { + gsl_Expects( file_ != nullptr ); + return std::fgetc( file_.get() ); + } + ... +}; +``` + +This is very tedious, not least because we have to define move constructor and move assignment operator manually. + +By using `not_null<>`, we can instead "lift" these preconditions to the type system and have all the +precondition checks be generated automatically: + +```c++ +class FileHandle // still movable +{ +private: + not_null<FilePtr> file_; // <-- + +public: + // implicit precondition check `rhs.file_ != nullptr` + FileHandle( FileHandle & rhs ) = default; + + // implicit precondition check `rhs.file_ != nullptr` + FileHandle & operator =( FileHandle & rhs ) = default; + + explicit FileHandle( not_null<FilePtr> _file ) // <-- + : file_( std::move( _file ) ) + { + // implicit precondition check `_file != nullptr` + } + int getc() + { + // implicit precondition check `file_ != nullptr` + return std::fgetc( file_.get() ); + } + ... +}; +``` + +Any code constructing a `FileHandle` will now have to explicitly cast the pointer as `not_null`: +```c++ +auto filePtr = FilePtr( std::fopen( ... ) ); +if ( filePtr == nullptr ) throw std::runtime_error( ... ); +auto file = FileHandle( not_null( std::move( filePtr ) ) ); +``` +But any function accepting a `FileHandle` can now be sure that the object holds a valid pointer: +```c++ +std::vector<std::string> +readLines( FileHandle file ) +{ + // file cannot hold a nullptr here + ... +} +``` + +Although `not_null<>` can be used to inject preconditions and postconditions, it does not inject new +invariants. After being moved from, a `FileHandle` indeed holds a `nullptr` in its `file_` pointer. +Therefore, non-nullability of the `file_` pointer is not an invariant of the `FileHandle` class. +However, a `FileHandle` is still safe to use because of the implicit precondition checks injected by `not_null<>`. +Also, *use-after-move* errors can often be detected by static analysis tools, so this may be considered +"safe enough" for practical purposes. + +<!--(Recommended further reading: Herb Sutter's article ["Move, simply"](https://herbsutter.com/2020/02/17/move-simply/), +which argues that objects that have a special moved-from state in which most of their operations may not be used +are buggy, and [Sean Parent's rebuttal](https://herbsutter.com/2020/02/17/move-simply/#comment-41129) in the comments below.)--> + +A `not_null<P>` cannot be directly compared to a `nullptr` because it is not meant to be nullable. +If you have to check for the moved-from state, use the `gsl_lite::is_valid()` predicate: +```c++ +auto npi = gsl_lite::make_unique<int>( 42 ); +// ... +//if ( npi == nullptr ) { ... } // compile error +if ( !gsl_lite::is_valid( npi ) ) { ... } // ok +``` + +*gsl-lite* also defines a set of helper functions `make_not_null()` for explicitly constructing `not_null<>` +objects. This is useful for type inference in C++14 and older where +[class template argument deduction](https://en.cppreference.com/w/cpp/language/class_template_argument_deduction) +is not available. Example: +```c++ +auto filePtr = FilePtr( std::fopen( ... ) ); +if ( filePtr == nullptr ) throw std::runtime_error( ... ); +auto file = FileHandle( make_not_null( std::move( filePtr ) ) ); +``` + + +### `not_null_ic<P>` + +(*Note:* `not_null_ic<>` is a *gsl-lite* extension and not part of the C++ Core Guidelines.) + +`gsl_lite::not_null_ic<P>` is a class template that wraps a pointer type `P` while enforcing non-nullability. +It provides all the guarantees and run-time checks of [`not_null<P>`](#not_nullp) but relaxes the requirements +of its conversion constructors: implicit conversion from `U` to `not_null_ic<P>` is allowed if `U` implicitly +converts to `P`. + +`not_null<>` does not allow implicit conversion from nullable types: +```c++ +void use( not_null<int *> p ); +int i; +//use( &i ); // compile error: no implicit conversion +use( not_null( &i ) ); // runtime check +``` + +This choice has the generally desirable consequence that it encourages propagation of non-nullability. +Explicit conversions are needed only when converting a nullable to a non-nullable pointer; therefore, as +more and more of a code base is converted to `not_null<>`, fewer explicit conversions need to be used. + +However, in some codebases it may not be feasible to insert explicit not-null checks at every invocation +site. In such a situation, `gsl_lite::not_null_ic<P>` can be used instead. `not_null_ic<P>` derives from `not_null<P>` +but additionally allows implicit construction from nullable types: + +```c++ +void use( not_null_ic<int *> p ); +int i; +use( &i ); // runtime check +``` + +(Compatibility note: Microsoft GSL defines the classes `not_null<>` and `strict_not_null<>` which behave +like *gsl-lite*'s `not_null_ic<>` and `not_null<>`, respectively.) + + +## Numeric type conversions + +(Core Guidelines reference: [GSL.util: Utilities](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#gslutil-utilities)) + +- [`narrow<T>( u )`](#narrowt-u-), a checked numeric cast +- [`narrow_failfast<T>( u )`](#narrow_failfastt-u-), a checked numeric cast +- [`narrow_cast<T>( u )`](#narrow_castt-u-), an unchecked numeric cast + +### `narrow<T>( u )` + +`gsl_lite::narrow<T>( u )` is a numeric cast that is not meant to be lossy. If narrowing leads to a change of sign or +loss of information, an exception of type `gsl_lite::narrowing_error` is thrown. + +**Example:** +```c++ +double volume = ...; // (m³) +double bucketCapacity = ...; // (m³) +double numBucketsF = std::ceil( volume/bucketCapacity ); +try +{ + auto numBuckets = gsl_lite::narrow<int>( numBucketsF ); + std::cout << "Number of buckets required: " << numBuckets; + fillBuckets( numBuckets ); +} +catch ( gsl_lite::narrowing_error const & ) +{ + std::cerr << "This is more than I can handle.\n"; +} +``` + +In this example, an exception will be thrown if `numBucketsF` is not an integer (for instance, `std::ceil(-INFINITY)` will return `-INFINITY`), +or if the value cannot be represented by `int`. + + +### `narrow_failfast<T>( u )` + +(*Note:* `narrow_failfast<T>( u )` is a *gsl-lite* extension and not part of the C++ Core Guidelines.) + +`gsl_lite::narrow_failfast<T>( u )` is a numeric cast that is not meant to be lossy, which is verified with +[`gsl_Assert()`](#contract-and-assertion-checks). If narrowing leads to a change of sign or loss of information, an +assertion violation is triggered. + +The `narrow<T>( u )` function specified by the C++ Core Guidelines throws an exception, thereby indicating exceptional circumstances +(for instance, "input data too large"). The exception may be caught and dealt with at runtime. Contrariwise, the purpose of +`narrow_failfast<T>( u )` is to detect programming errors which the user of the program cannot do anything about. + +**Example 1:** +```c++ +void printCmdArgs( gsl_lite::span<gsl_lite::zstring const> cmdArgs ); + +int main( int argc, char * argv[] ) +{ + auto args = gsl_lite::span( + argv, + // Something is seriously wrong if this cast fails. + gsl_lite::narrow_failfast<std::size_t>( argc ) ); + printCmdArgs( args ); +} +``` + +**Example 2:** +```c++ +auto vec = std::vector{ 1, 2, 3 }; +int elem = 2; +auto pos = std::find( vec.begin(), vec.end(), elem ); + + // Bug: we accidentally swapped `pos` and `vec.end()`. +auto delta = pos - vec.end(); + + // Assertion violation: `delta` is negative. +auto subrangeSize = gsl_lite::narrow_failfast<std::size_t>( delta ); + +auto subrange = std::vector<int>( subrangeSize ); +``` + + +### `narrow_cast<T>( u )` + +`narrow_cast<T>( u )` is a numeric cast in which loss of information is acceptable. It is exactly equivalent to `static_cast<T>( u )`, +the only difference being that `narrow_cast<>()` conveys the intent that truncation or sign change is acceptable or even desired. + +**Example 1:** +```c++ + // Sign change to 0xFFFFFFFF +auto allBitsSet = gsl_lite::narrow_cast<std::uint32_t>( -1 ); +``` + +**Example 2:** +```c++ +int floor( float val ) +{ + gsl_Expects( + val >= std::numeric_limits<int>::lowest() && + val <= std::numeric_limits<int>::max() ); + + return gsl_lite::narrow_cast<int>( val ); // truncation is desired here +} +``` + + +## Safe contiguous ranges + +(Core Guidelines reference: [GSL.view: Views](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#gslview-views)) + +*gsl-lite* defines a class `gsl_lite::span<T, Extent>` that represents a contiguous sequence of objects. The interface +of `span<>` is identical to that of [`std::span<>`](https://en.cppreference.com/w/cpp/container/span), +but all operations in *gsl-lite*'s `span<>` use [`gsl_Expects()`](#contract-and-assertion-checks) to +check their preconditions at runtime. `span<>::iterator` also verifies the preconditions of all its operations +with `gsl_ExpectsDebug()`. + +*gsl-lite* also defines a set of helper functions `make_span()` for explicitly constructing `span<>` objects. This is useful +for type inference in C++14 and older where [class template argument deduction](https://en.cppreference.com/w/cpp/language/class_template_argument_deduction) +is not available. Example: +```c++ +void printCmdArgs( gsl_lite::span<gsl_lite::zstring const> cmdArgs ); + +int main( int argc, char * argv[] ) +{ + auto args = gsl_lite::make_span( + argv, gsl_lite::narrow_failfast<std::size_t>( argc ) ); + printCmdArgs( args ); +} +``` + +## Bounds-checked element access + +(Core Guidelines reference: [GSL.util: Utilities](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#gslutil-utilities)) + +The function `gsl_lite::at( container, index )` offers bounds-checked element access for all sized containers with random access. +Exposition-only definition: + +```c++ +template< class Container > +auto at( Container& c, index i ) +{ + gsl_Expects( i >= 0 && i < std::ssize( c ) ); + return c[ i ]; +} +``` + + +## Integer type aliases + +(Core Guidelines reference: [GSL.util: Utilities](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#gslutil-utilities)) + +(*Note:* `dim`, `stride`, and `diff` are *gsl-lite* extensions and not part of the C++ Core Guidelines.) + +[Rule ES.107](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Res-subscripts) of the C++ Core Guidelines suggests, +"Don't use `unsigned` for subscripts, prefer `gsl::index`," giving several good reasons for preferring a signed over an unsigned +type for indexing. For this purpose, the GSL defines `index` as a type alias for `std::ptrdiff_t`. + +*gsl-lite* defines the type alias `gsl_lite::index` along with the aliases `gsl_lite::dim`, `gsl_lite::stride`, and `gsl_lite::diff`: + +Type alias | Purpose | +----------:|:-----------------------------------------------| +`index` | Signed integer type for indexes and subscripts | +`dim` | Signed integer type for sizes | +`stride` | Signed integer type for index strides | +`diff` | Signed integer type for index differences | + +**Example:** +```c++ +auto x = std::vector<double>{ ... }; +auto dx = std::vector<double>( x.size() - 1 ); +gsl_lite::dim n = std::ssize( x ); +for ( gsl_lite::index i = 0; i < n - 1; ++i ) +{ + dx[ i ] = x[ i + 1 ] - x[ i ]; +} +``` + +`index`, `dim`, `stride`, and `diff` are all aliases for `std::ptrdiff_t` unless the [`gsl_CONFIG_INDEX_TYPE`](#gsl_config_index_typestdptrdiff_t) +configuration macro is set to a different type (which is not recommended). + + +## String type aliases + +(Core Guidelines reference: [GSL.view: Views](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#gslview-views)) + +(*Note:* `wzstring` and `cwzstring` are *gsl-lite* extensions and not part of the C++ Core Guidelines.) + +*gsl-lite* defines the aliases `gsl_lite::zstring`, `gsl_lite::czstring`, `gsl_lite::wzstring`, and `gsl_lite::cwzstring` for +C-style strings (where a C-style string is understood to be either a zero-terminated sequence of characters or a `nullptr`): + +Type alias | Type | +-----------:|:------------------| +`zstring` | `char *` | +`czstring` | `char const *` | +`wzstring` | `wchar_t *` | +`cwzstring` | `wchar_t const *` | + + +## Ad hoc resource management (C++11 and higher) + +(Core Guidelines reference: [GSL.util: Utilities](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#gslutil-utilities)) + +(*Note:* `on_return()` and `on_error()` are *gsl-lite* extensions and not part of the C++ Core Guidelines.) + +*gsl-lite* defines the following helpers for ad hoc resource management: + +- `gsl_lite::finally( action )` constructs and returns an object which invokes `action` upon destruction. +- `gsl_lite::on_return( action )` constructs and returns an object which invokes `action` upon destruction only if no exception was thrown. +- `gsl_lite::on_error( action )` constructs and returns an object which invokes `action` upon destruction only if an exception was thrown. + +[Rule R.1](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#r1-manage-resources-automatically-using-resource-handles-and-raii-resource-acquisition-is-initialization) +of the C++ Core Guidelines suggests: "Manage resources automatically using resource handles and [RAII](https://en.cppreference.com/w/cpp/language/raii) +(Resource Acquisition Is Initialization)". While this advice is sound, it may sometimes be inconvenient to always define a resource handle type +for every situation in which a resource needs to be cleaned up. + +For example, we might wish to modernize the following code which uses the [C standard library](https://en.cppreference.com/w/cpp/header/cstdio) +to read from a file: +```c++ +std::vector<std::string> readLines( char const * filename ) +{ + std::FILE * file = std::fopen( filename, "r" ); + if ( !file ) throw std::runtime_error( ... ); + std::vector<std::string> result; + ... // implementation omitted + std::fclose( file ); + return result; +} +``` +This code is not exception-safe: if the (omitted) implementation throws an exception, `fclose()` is never called on the `file` handle. +The problem of exception safety is typically addressed by defining a resource handle type for `FILE` +(see the [`FileHandle` example above](#nullability-and-the-moved-from-state)): +```c++ +struct FileCloser +{ + void operator ()(std::FILE* file) const noexcept + { + std::fclose( file ); + } +}; +using FilePtr = std::unique_ptr<std::FILE, FileCloser>; + +std::vector<std::string> readLines( char const * filename ) +{ + auto file = FilePtr( std::fopen( filename, "r" ) ); + if ( !file ) throw std::runtime_error( ... ); + std::vector<std::string> result; + ... // implementation omitted + return result; +} +``` + +Alternatively, we can fix the problem by using `gsl_lite::finally()`: +```c++ +std::vector<std::string> readLines( char const * filename ) +{ + std::FILE * file = std::fopen( filename, "r" ); + if ( !file ) throw std::runtime_error( ... ); + auto _ = gsl_lite::finally( [&] { std::fclose( file ); } ); + std::vector<std::string> result; + ... // implementation omitted + return result; +} +``` +The destructor of the local object `_` will call `std::fclose( file )` regardless of whether the function returns normally or is +interrupted by an exception. This ensures that the `file` handle does not leak. + + +## Feature checking macros + +(*Note:* Feature checking macros are a *gsl-lite* extension and not part of the C++ Core Guidelines.) + +The following preprocessor macros can be used to identify features of the C++ build environment: + +Name | Meaning | +---------------------------------------:|:----------------| +**Metadata:** | | +`gsl_lite_MAJOR` | Major version number of *gsl-lite* | +`gsl_lite_MINOR` | Minor version number of *gsl-lite* | +`gsl_lite_PATCH` | Patch version number of *gsl-lite* | +`gsl_lite_VERSION` | A string holding the semantic version number \<major\>.\<minor\>.\<patch\> of *gsl-lite* (e.g. `"1.0.0"`) | +**Language and library support:** | | +`gsl_CPPxx_OR_GREATER` | Whether C++xx language features are available<br>(substitute `11`, `14`, `17`, `20`, `23`, `26`) | +`gsl_STDLIB_CPPXX_OR_GREATER` | Whether C++xx standard library features are available<br>(substitute `11`, `14`, `17`, `20`, `23`, `26`) | +**Compiler version detection:** | | +`gsl_BETWEEN( V, L, H )` | V ≥ L and V < H | +`gsl_COMPILER_GNUC_VERSION` | Evaluates to version number when compiled with GNU GCC, 0 otherwise | +`gsl_COMPILER_CLANG_VERSION` | Evaluates to version number when compiled with Clang, 0 otherwise | +`gsl_COMPILER_MSVC_VERSION` | Evaluates to version number when compiled with Microsoft Visual C++, 0 otherwise | +`gsl_COMPILER_APPLECLANG_VERSION` | Evaluates to version number when compiled with Apple Clang, 0 otherwise | +`gsl_COMPILER_NVCC_VERSION` | Evaluates to version number when compiled with NVIDIA NVCC, 0 otherwise | +`gsl_COMPILER_ARMCC_VERSION` | Evaluates to version number when compiled with ARMCC, 0 otherwise | +`gsl_DEVICE_CODE` | Whether CUDA device code is being compiled | +`gsl_HAVE( EXCEPTIONS )` | Evaluates to 1 if exceptions are available, 0 when compiling with exceptions disabled | +`gsl_HAVE( WCHAR )` | Evaluates to 1 if `wchar_t` type is available, 0 otherwise | + +When a new revision of the C++ language is standardized, features often become available gradually in compilers and standard libraries. +C\+\+20 introduces a set of preprocessor macros to check for the availability of [language features](https://en.cppreference.com/w/cpp/feature_test) +and [standard library features](https://en.cppreference.com/w/cpp/feature_test#Library_features); but such macros are not necessarily available in +implementations predating C\+\+20. For this purpose, *gsl-lite* defines a limited set of feature checking macros. +They all follow the pattern `gsl_HAVE( xx )`, where `xx` is to be replaced by a token representing a given language feature. `gsl_HAVE( xx )` evaluates +to 1 if the corresponding language or library feature is available, 0 otherwise. + +Name | Feature | +---------------------------------------:|:----------------| +**Language features:** | | +`gsl_HAVE( C99_PREPROCESSOR )` | C99-compatible [preprocessor](https://en.cppreference.com/w/c/preprocessor) | +`gsl_HAVE( AUTO )` | [`auto`](https://en.cppreference.com/w/cpp/language/auto) (C++11) | +`gsl_HAVE( RVALUE_REFERENCE )` | [rvalue references](https://en.cppreference.com/w/cpp/language/reference) (C++11) | +`gsl_HAVE( FUNCTION_REF_QUALIFIER )` | [ref-qualified member functions](https://en.cppreference.com/w/cpp/language/member_functions) (C++11) | +`gsl_HAVE( ENUM_CLASS )` | [`enum class`](https://en.cppreference.com/w/cpp/language/enum) (C++11) | +`gsl_HAVE( ALIAS_TEMPLATE )` | [alias templates](https://en.cppreference.com/w/cpp/language/type_alias) (C++11) | +`gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG )` | [default template arguments for function templates](https://en.cppreference.com/w/cpp/language/function_template) (C++11) | +`gsl_HAVE( EXPLICIT )` | [`explicit`](https://en.cppreference.com/w/cpp/language/explicit) specifier (C++11) | +`gsl_HAVE( VARIADIC_TEMPLATE )` | [variadic templates](https://en.cppreference.com/w/cpp/language/pack) (C++11) | +`gsl_HAVE( IS_DELETE )` | [deleted functions](https://en.cppreference.com/w/cpp/keyword/delete) (C++11) | +`gsl_HAVE( IS_DEFAULT )` | [explicitly defaulted functions](https://en.cppreference.com/w/cpp/keyword/default) (C++11) | +`gsl_HAVE( NOEXCEPT )` | [`noexcept`](https://en.cppreference.com/w/cpp/language/noexcept_spec) specifier and [`noexcept()`](https://en.cppreference.com/w/cpp/language/noexcept) operator (C++11) | +`gsl_HAVE( NORETURN )` | [`[[noreturn]]`](https://en.cppreference.com/w/cpp/language/attributes/noreturn) attribute (C++11) | +`gsl_HAVE( EXPRESSION_SFINAE )` | [expression SFINAE](https://en.cppreference.com/w/cpp/language/sfinae) | +`gsl_HAVE( OVERRIDE_FINAL )` | [`override`](https://en.cppreference.com/w/cpp/language/override) and [`final`](https://en.cppreference.com/w/cpp/language/final) specifiers (C++11) | +`gsl_HAVE( DECLTYPE_AUTO )` | [`decltype(auto)`](https://en.cppreference.com/w/cpp/language/decltype) (C++11) | +`gsl_HAVE( DEPRECATED )` | [`[[deprecated]]`](https://en.cppreference.com/w/cpp/language/attributes/deprecated) attribute (C++11) | +`gsl_HAVE( ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE )` | constructing `enum class` from the underlying type (C++17) | +`gsl_HAVE( DEDUCTION_GUIDES )` | [`class template argument deduction`](https://en.cppreference.com/w/cpp/language/class_template_argument_deduction) guides (C++17) | +`gsl_HAVE( NODISCARD )` | [`[[nodiscard]]`](https://en.cppreference.com/w/cpp/language/attributes/nodiscard) attribute (C++17) | +`gsl_HAVE( MAYBE_UNUSED )` | [`[[maybe_unused]]`](https://en.cppreference.com/w/cpp/language/attributes/maybe_unused) attribute (C++17) | +`gsl_HAVE( CONSTEXPR_xx )` | C++xx [`constexpr`](https://en.cppreference.com/w/cpp/language/constexpr) features (substitute `11`, `14`, `17`, `20`, `23`, `26`) | +**Standard library features:** | | +`gsl_HAVE( ADDRESSOF )` | [`std::addressof()`](https://en.cppreference.com/w/cpp/memory/addressof) (C++11) | +`gsl_HAVE( ARRAY )` | [`std::array<>`](https://en.cppreference.com/w/cpp/container/array) (C++11) | +`gsl_HAVE( TYPE_TRAITS )` | [`<type_traits>`](https://en.cppreference.com/w/cpp/header/type_traits) header (C++11) | +`gsl_HAVE( CONTAINER_DATA_METHOD )` | `data()` member function on containers | +`gsl_HAVE( STD_DATA )` | [`std::data()`](https://en.cppreference.com/w/cpp/iterator/data) (C++17) | +`gsl_HAVE( STD_SSIZE )` | [`std::ssize()`](https://en.cppreference.com/w/cpp/iterator/size) (C++20) | +`gsl_HAVE( HASH )` | [`std::hash<>`](https://en.cppreference.com/w/cpp/utility/hash) (C++11) | +`gsl_HAVE( SIZED_TYPES )` | [sized integer type aliases]() (C++11) | +`gsl_HAVE( SHARED_PTR )` | [`std::shared_ptr<>`](https://en.cppreference.com/w/cpp/memory/shared_ptr) (C++11) | +`gsl_HAVE( UNIQUE_PTR )` | [`std::unique_ptr<>`](https://en.cppreference.com/w/cpp/memory/unique_ptr) (C++11) | +`gsl_HAVE( MAKE_SHARED )` | [`std::make_shared<>()`](https://en.cppreference.com/w/cpp/memory/shared_ptr/make_shared) (C++11) | +`gsl_HAVE( MAKE_UNIQUE )` | [`std::make_unique<>()`](https://en.cppreference.com/w/cpp/memory/unique_ptr/make_unique) (C++14) | +`gsl_HAVE( MOVE_FORWARD )` | [`std::move()`](https://en.cppreference.com/w/cpp/utility/move) and [`std::forward<>()`](https://en.cppreference.com/w/cpp/utility/forward) (C++11) | +`gsl_HAVE( NULLPTR )` | [`nullptr`](https://en.cppreference.com/w/cpp/language/nullptr) keyword (C++11) | +`gsl_HAVE( UNCAUGHT_EXCEPTIONS )` | [`std::uncaught_exceptions()`](https://en.cppreference.com/w/cpp/error/uncaught_exception) (C++17) | +`gsl_HAVE( INITIALIZER_LIST )` | [`std::initializer_list<>`](https://en.cppreference.com/w/cpp/utility/initializer_list) (C++11) | +`gsl_HAVE( REMOVE_CVREF )` | [`std::remove_cvref<>`](https://en.cppreference.com/w/cpp/types/remove_cvref) (C++20) | + + +## Polyfills + +(*Note:* Polyfills are a *gsl-lite* extension and not part of the C++ Core Guidelines.) + +*gsl-lite* defines some macros, types, and functions for use with earlier versions of C++: + +- [Keyword and attribute macros](#keyword-and-attribute-macros) +- [Code generation macros](#code-generation-macros) +- [Types and functions](#types-and-functions) + +### Keyword and attribute macros + +The keyword and attribute macros allow to conditionally take advantage of newer language features if available: + +Name | Expands to | +---------------------------:|:----------------| +`gsl_DIMENSION_OF( a )` | `( sizeof( a ) / sizeof( 0[ a ] ) )`, which is the number of elements in a C-style array `a` | +`gsl_constexpr` | [`constexpr`](https://en.cppreference.com/w/cpp/language/constexpr) in C++11 and higher, to nothing otherwise | +`gsl_constexprXX` | [`constexpr`](https://en.cppreference.com/w/cpp/language/constexpr) in C++XX and higher, to nothing otherwise<br>(substitute 14, 17, 20, 23, 26) | +`gsl_explicit` | [`explicit`](https://en.cppreference.com/w/cpp/language/explicit) specifier in C++11 and higher, to nothing otherwise | +`gsl_is_delete` | `= delete` in C++11 and higher, to nothing otherwise | +`gsl_is_delete_access` | `public` in C++11 and higher, to `private` otherwise | +`gsl_noexcept` | [`noexcept`](https://en.cppreference.com/w/cpp/language/noexcept_spec) specifier in C++11 and higher, to nothing otherwise | +`gsl_noexcept_if( expr )` | [`noexcept( expr )`](https://en.cppreference.com/w/cpp/language/noexcept) operator in C++11 and higher, to nothing otherwise | +`gsl_nullptr` | `nullptr` in C++11 and higher, to `NULL` otherwise | +`gsl_NORETURN` | [`[[noreturn]]`](https://en.cppreference.com/w/cpp/language/attributes/noreturn) attribute in C++11 and higher, to a compiler-specific attribute if available, or to nothing otherwise | +`gsl_DEPRECATED` | [`[[deprecated]]`](https://en.cppreference.com/w/cpp/language/attributes/deprecated) attribute in C++14 and higher, to nothing otherwise | +`gsl_DEPRECATED_MSG( msg )` | [`[[deprecated( msg )]]`](https://en.cppreference.com/w/cpp/language/attributes/deprecated) attribute in C++14 and higher, to nothing otherwise | +`gsl_NODISCARD` | [`[[nodiscard]]`](https://en.cppreference.com/w/cpp/language/attributes/nodiscard) attribute in C++17 and higher, to nothing otherwise | +`gsl_MAYBE_UNUSED` | [`[[maybe_unused]]`](https://en.cppreference.com/w/cpp/language/attributes/maybe_unused) attribute in C++17 and higher, or to nothing otherwise | +`gsl_MAYBE_UNUSED_MEMBER` | [`[[maybe_unused]]`](https://en.cppreference.com/w/cpp/language/attributes/maybe_unused) attribute in C++17 and higher if that attribute does not raise a warning when applied to class data members (as is the case for GNU GCC), or to nothing otherwise | +`gsl_NO_UNIQUE_ADDRESS`<br>(≥ C++20) | [`[[msvc::no_unique_address]]`](https://devblogs.microsoft.com/cppblog/msvc-cpp20-and-the-std-cpp20-switch/) for MSVC, to [`[[no_unique_address]]`](https://en.cppreference.com/w/cpp/language/attributes/no_unique_address) otherwise | + +### Code generation macros + +The following macros help avoid writing repetitive code: + +- `gsl_DEFINE_ENUM_BITMASK_OPERATORS( e )`: + Defines bitmask operators `|`, `&`, `^`, `~`, `|=`, `&=`, and `^=` for the enum type `e`. + Example: + ```c++ + enum class Vegetables + { + tomato = 0b001, + onion = 0b010, + eggplant = 0b100 + }; + gsl_DEFINE_ENUM_BITMASK_OPERATORS( Vegetables ) + ``` + +- `gsl_DEFINE_ENUM_RELATIONAL_OPERATORS( e )`: + Defines relational operators (`<=>` in C++20 and newer, `<`, `>`, `<=`, and `>=` otherwise) for the enum type `e`. + Example: + ```c++ + enum class OperatorPrecedence + { + additive = 0, + multiplicative = 1, + power = 2 + }; + gsl_DEFINE_ENUM_RELATIONAL_OPERATORS( OperatorPrecedence ) + ``` + +### Types and functions + +The following types and functions implement some functionality added only in later C++ standards: + +Name | C++ feature | +-------------------------------------------------:|:----------------| +`gsl_lite::std11::add_const<>` | [`std::add_const<>`](https://en.cppreference.com/w/cpp/types/add_cv) (C++11) | +`gsl_lite::std11::remove_const<>`<br>`std11::remove_volatile<>`<br>`std11::remove_cv<>` | [`std::remove_const<>`](https://en.cppreference.com/w/cpp/types/remove_cv) (C++11)<br>[`std::remove_volatile<>`](https://en.cppreference.com/w/cpp/types/remove_cv) (C++11)<br>[`std::remove_cv<>`](https://en.cppreference.com/w/cpp/types/remove_cv) (C++11) | +`gsl_lite::std11::remove_reference<>` | [`std::remove_reference<>`](https://en.cppreference.com/w/cpp/types/remove_reference) (C++11) | +`gsl_lite::std11::integral_constant<>`<br>`gsl_lite::std11::true_type`<br>`gsl_lite::std11::false_type`<br>`gsl_lite::std17::bool_constant<>`| [`std::integral_constant<>`](https://en.cppreference.com/w/cpp/types/integral_constant) (C++11)<br>[`std::true_type`](https://en.cppreference.com/w/cpp/types/integral_constant) (C++11)<br>[`std::false_type`](https://en.cppreference.com/w/cpp/types/integral_constant) (C++11)<br>[`std::bool_constant<>`](https://en.cppreference.com/w/cpp/types/integral_constant) (C++17) | +`gsl_lite::std14::make_unique<>()` | [`std::make_unique<>()`](https://en.cppreference.com/w/cpp/memory/unique_ptr/make_unique) (C++14) | +`gsl_lite::std17::uncaught_exceptions()` | [`std::uncaught_exceptions()`](https://en.cppreference.com/w/cpp/error/uncaught_exception) (C++17) | +`gsl_lite::std17::negation<>` | [`std::negation<>`](https://en.cppreference.com/w/cpp/types/negation) (C++17) | +`gsl_lite::std17::conjunction<>` (≥ C\+\+11) | [`std::conjunction<>`](https://en.cppreference.com/w/cpp/types/conjunction) (C++17) | +`gsl_lite::std17::disjunction<>` (≥ C\+\+11) | [`std::disjunction<>`](https://en.cppreference.com/w/cpp/types/disjunction) (C++17) | +`gsl_lite::std17::void_t<>` (≥ C\+\+11) | [`std::void_t<>`](https://en.cppreference.com/w/cpp/types/void_t) (C++17) | +`gsl_lite::size()`, `gsl_lite::std17::size()`<br>`gsl_lite::ssize()`, `gsl_lite::std20::ssize()` | [`std::size()`](https://en.cppreference.com/w/cpp/iterator/size) (C++17)<br>[`std::ssize()`](https://en.cppreference.com/w/cpp/iterator/size) (C++20) | +`gsl_lite::data()`, `gsl_lite::std17::data()` | [`std::data()`](https://en.cppreference.com/w/cpp/iterator/data) (C++17) | +`gsl_lite::std20::endian` | [`std::endian`](https://en.cppreference.com/w/cpp/types/endian) (C++20) | +`gsl_lite::type_identity<>`, `gsl_lite::std20::type_identity<>` | [`std::type_identity<>`](https://en.cppreference.com/w/cpp/types/type_identity) (C++20) | +`gsl_lite::identity`, `gsl_lite::std20::identity` | [`std::identity`](https://en.cppreference.com/w/cpp/utility/functional/identity) (C++20) | +`gsl_lite::std20::remove_cvref<>` | [`std::remove_cvref<>`](https://en.cppreference.com/w/cpp/types/remove_cvref) (C++20) | + + +## Configuration options and switches + +- [Contract checking configuration macros](#contract-checking-configuration-macros) + - [Runtime enforcement](#runtime-enforcement) + - [Contract violation handling](#contract-violation-handling) + - [Unenforced contract checks](#unenforced-contract-checks) +- [Feature selection macros](#feature-selection-macros) +- [Other configuration macros](#other-configuration-macros) + +*gsl-lite* is customizable through a large number of configuration options and switches. +The configuration of contract checks may be useful for various purposes (performance, unit testing, fail-safe environments). +The main purpose of the other configuration options is backward compatibility. + +The configuration macros may affect the API and ABI of *gsl-lite* in ways that renders it incompatible with other code. +Therefore, as a general rule, **do not define, or rely on, any of *gsl-lite*'s configuration options or switches when using *gsl-lite* in a library**. + +### Contract checking configuration macros + +With the configuration macros described in the following sections, the user can exert fine-grained control over the runtime behavior +of contract checks expressed with [`gsl_Expects()`, `gsl_Ensures()`, `gsl_Assert()` and other contract checking macros](#contract-and-assertion-checks). +The configuration options for contract violation response follow the suggestions originally suggested in proposal [N4415](http://wg21.link/n4415), +with some refinements inspired by [P1710](http://wg21.link/P1710)/[P1730](http://wg21.link/P1730). + + +#### Runtime enforcement + +The following macros control whether contracts are checked at runtime: + +- **`gsl_CONFIG_CONTRACT_CHECKING_AUDIT`** + Define this macro to have contracts expressed with `gsl_ExpectsAudit()`, `gsl_EnsuresAudit()`, and `gsl_AssertAudit()` checked + at runtime. + +- **`gsl_CONFIG_CONTRACT_CHECKING_ON` (default)** + Define this macro to have contracts expressed with `gsl_Expects()`, `gsl_Ensures()`, `gsl_Assert()`, and `gsl_FailFast()` + checked at runtime, Contracts expressed with `gsl_ExpectsDebug()`, `gsl_EnsuresDebug()`, and `gsl_AssertDebug()` are also + checked at runtime (unless `NDEBUG` is defined and `gsl_CONFIG_CONTRACT_CHECKING_AUDIT` is not). + **This is the default.** + +- **`NDEBUG`** + This macro traditionally disables runtime checks for the [`assert()`](https://en.cppreference.com/w/c/error/assert) macro from + the C standard library. Additionally, contracts expressed with `gsl_ExpectsDebug()`, `gsl_EnsuresDebug()`, and `gsl_AssertDebug()` + are not evaluated or checked at runtime if `NDEBUG` is defined and `gsl_CONFIG_CONTRACT_CHECKING_AUDIT` is not. + +- **`gsl_CONFIG_CONTRACT_CHECKING_OFF`** + Define this macro to disable all runtime checking of contracts and invariants. + + Note that `gsl_FailFast()` checks will trigger runtime failure even if runtime checking is disabled. + +- If desired, the macros **`gsl_CONFIG_DEVICE_CONTRACT_CHECKING_AUDIT`**, **`gsl_CONFIG_DEVICE_CONTRACT_CHECKING_ON`**, and + **`gsl_CONFIG_DEVICE_CONTRACT_CHECKING_OFF`** can be used to configure contract checking for CUDA device code separately. If + neither of these macros is defined, device code uses the same configuration as host code. + + It may be reasonable to define `gsl_CONFIG_DEVICE_CONTRACT_CHECKING_OFF` in Release builds because the performance impact of + runtime checks can be grave in device code, while it is often negligible in host code. + +The following macros can be used to selectively disable checking for a particular kind of contract: + +- **`gsl_CONFIG_CONTRACT_CHECKING_EXPECTS_OFF`** + Define this macro to disable runtime checking of precondition contracts expressed with `gsl_Expects()`, `gsl_ExpectsDebug()`, and `gsl_ExpectsAudit()`. + +- **`gsl_CONFIG_CONTRACT_CHECKING_ENSURES_OFF`** + Define this macro to disable runtime checking of postcondition contracts expressed with `gsl_Ensures()`, `gsl_EnsuresDebug()`, and `gsl_EnsuresAudit()`. + +- **`gsl_CONFIG_CONTRACT_CHECKING_ASSERT_OFF`** + Define this macro to disable runtime checking of assertions expressed with `gsl_Assert()`, `gsl_AssertDebug()`, and `gsl_AssertAudit()`. + + +#### Contract violation handling + +The following macros control the handling of runtime contract violations: + +- **`gsl_CONFIG_CONTRACT_VIOLATION_ASSERTS` (default)** + If this macro is defined, and if the `assert()` macro is available for runtime checks (that is, if `NDEBUG` is not defined), + contract checking macros are implemented in terms of `assert()`. If `assert()` is unavailable (i.e. if `NDEBUG` was defined), + `std::abort()` is called directly when a contract is violated. + **This is the default.** + + This option may be preferable over `gsl_CONFIG_CONTRACT_VIOLATION_TERMINATES` because `assert()` prints diagnostic information + (such as the current source file, a line number, and the function name), and because vendor-specific extensions of `assert()` + can be used (for instance, the `assert()` implementation of the Microsoft C runtime displays a dialog box which permits breaking + into the debugger or continuing execution). + + Note that `gsl_FailFast()` will call `std::abort()` if `assert()` continues execution. + +- **`gsl_CONFIG_CONTRACT_VIOLATION_TERMINATES`** + Define this macro to call `std::terminate()` on a contract violation. + +- **`gsl_CONFIG_CONTRACT_VIOLATION_TRAPS`** + Define this macro to execute a trap instruction on a contract violation. + + Trap instructions may yield smaller codegen and can thus result in better-performing code. However, they usually lead to + catastrophic failure and may be difficult to diagnose for some platforms. + +- **`gsl_CONFIG_CONTRACT_VIOLATION_THROWS`** + Define this macro to throw a `std::runtime_error`-derived exception `gsl_lite::fail_fast` on contract violation. + Handling contract violations with exceptions can be desirable when executing in an interactive programming environment, or if + there are other reasons why process termination must be avoided. + + This setting is also useful for writing unit tests that exercise contract checks. + +- **`gsl_CONFIG_CONTRACT_VIOLATION_CALLS_HANDLER`** + Define this macro to call a user-defined handler function `gsl_lite::fail_fast_assert_handler()` on a contract violation. + The user must provide a definition of the following function: + ```c++ + namespace gsl_lite { + gsl_api void fail_fast_assert_handler( + char const * expression, char const * message, + char const * file, int line ); + } // namespace gsl_lite + ``` + + Note that `gsl_FailFast()` will call `std::terminate()` if `fail_fast_assert_handler()` returns. + +- If desired, the macros **`gsl_CONFIG_DEVICE_CONTRACT_VIOLATION_ASSERTS`**, **`gsl_CONFIG_DEVICE_CONTRACT_VIOLATION_TRAPS`**, and + **`gsl_CONFIG_DEVICE_CONTRACT_VIOLATION_CALLS_HANDLER`** can be used to configure contract violation handling for CUDA device + code separately. If neither of these macros is defined, device code uses the following defaults: + - `gsl_CONFIG_CONTRACT_VIOLATION_TERMINATES` → `gsl_CONFIG_DEVICE_CONTRACT_VIOLATION_ASSERTS` + - `gsl_CONFIG_CONTRACT_VIOLATION_ASSERTS` → `gsl_CONFIG_DEVICE_CONTRACT_VIOLATION_ASSERTS` + - `gsl_CONFIG_CONTRACT_VIOLATION_THROWS` → `gsl_CONFIG_DEVICE_CONTRACT_VIOLATION_ASSERTS` + - `gsl_CONFIG_CONTRACT_VIOLATION_TRAPS` → `gsl_CONFIG_DEVICE_CONTRACT_VIOLATION_TRAPS` + - `gsl_CONFIG_CONTRACT_VIOLATION_CALLS_HANDLER` → `gsl_CONFIG_DEVICE_CONTRACT_VIOLATION_CALLS_HANDLER` + + +#### Unenforced contract checks + +The following macros control what happens with individual contract checks which are not enforced at runtime. Note that these +macros do not disable runtime contract checking; they only configure what happens to contracts which are not checked as a result +of configuration, e.g. for any contract check if `gsl_CONFIG_CONTRACT_CHECKING_OFF` is defined, or for audit-level and debug-level +contract checks if `NDEBUG` is defined. + +- **`gsl_CONFIG_UNENFORCED_CONTRACTS_ELIDE` (default)** + Contract checks disabled by configuration will be discarded. + **This is the default.** + + Note that `gsl_FailFast()` calls are never discarded. + + Even for discarded contract checks, *gsl-lite* will by default still verify that the contract check forms a valid Boolean + expression using the C++11 features `decltype()` and `static_assert()`. This may lead to problems if the contract check + expression cannot be used in an unevaluated context, for instance, when using a lambda expression in C++11/14/17. + + The compile-time verification of contract check expressions is controlled by the configuration macro + `gsl_CONFIG_VALIDATES_UNENFORCED_CONTRACT_EXPRESSIONS`, which defaults to *`1`*. To suppress the verification, define + `gsl_CONFIG_VALIDATES_UNENFORCED_CONTRACT_EXPRESSIONS=0`. + +- **`gsl_CONFIG_UNENFORCED_CONTRACTS_ASSUME`** + For contracts expressed with `gsl_Expects()`, `gsl_Ensures()`, and `gsl_Assert()` which are not checked as a result of + configuration, instruct the compiler to assume that they always hold true. This is expressed with compiler-specific intrinsics + such as `__assume()`. + + Contract checks expressed with `gsl_ExpectsDebug()`, `gsl_EnsuresDebug()`, `gsl_AssertDebug()` , `gsl_ExpectsAudit()`, + `gsl_EnsuresAudit()`, and `gsl_AssertAudit()` which are not checked at runtime (due to definition of `NDEBUG` or one of the + aforementioned configuration macros) are discarded. + + Explicitly injecting the assumption that contracts hold true implies that violating contracts causes undefined behavior. This + may give the compiler more opportunities for optimization, but it is usually dangerous and, like all occurrences of undefined + behavior, it can have devastating consequences. + + The use of compiler-specific "assume" intrinsics may lead to spurious runtime evaluation of contract expressions. Because + *gsl-lite* implements contract checks with macros (rather than as a language feature as the defunct C++2a Contracts proposal + did), it cannot reliably suppress runtime evaluation for all compilers. For instance, if the contract check fed to the "assume" + intrinsic comprises a function call which is opaque to the compiler, many compilers will generate the runtime function call. + Therefore, `gsl_Expects()`, `gsl_Ensures()`, and `gsl_Assert()` should be used only for conditions that can be proven + side-effect-free by the compiler, and `gsl_ExpectsDebug()`, `gsl_EnsuresDebug()`, `gsl_AssertDebug()`, `gsl_ExpectsAudit()`, + `gsl_EnsuresAudit()`, and `gsl_AssertAudit()` for everything else. In practice, this means that `gsl_Expects()`, + `gsl_Ensures()`, and `gsl_Assert()` should only be used for simple comparisons of scalar values, for simple inlineable getters, + and for comparisons of class objects with trivially inlineable comparison operators. + + Revisiting the [example given above](#contract-and-assertion-checks): + ```c++ + template< class RandomIt > + auto median( RandomIt first, RandomIt last ) + { + // Comparing iterators for equality boils down to a comparison of pointers. An optimizing + // compiler will inline the comparison operator and understand that the comparison is free of + // side-effects, and hence generate no code in `gsl_CONFIG_UNENFORCED_CONTRACTS_ASSUME` mode. + gsl_Expects( first != last ); + + // If we cannot trust the compiler to understand that this function call is free of + // side-effects, we should use `gsl_ExpectsDebug()` or `gsl_ExpectsAudit()`. This particular + // function call is expensive, so we use an audit-level contract check. + gsl_ExpectsAudit( std::is_sorted( first, last ) ); + + auto count = last - first; + return count % 2 != 0 + ? first[ count / 2 ] + : std::midpoint( first[ count / 2 ], first[ count / 2 + 1 ] ); + } + ``` + +- If desired, the macros **`gsl_CONFIG_DEVICE_UNENFORCED_CONTRACTS_ELIDE`** and **`gsl_CONFIG_DEVICE_UNENFORCED_CONTRACTS_ASSUME`** + can be used to configure handling of unenforced contract checks for CUDA device code separately. If neither of these macros is + defined, device code uses the same configuration as host code. + + +### Feature selection macros + +#### `gsl_FEATURE_GSL_COMPATIBILITY_MODE=0` + +To minimize the impact of the breaking changes, *gsl-lite* v1.0 introduces an optional *GSL compatibility mode* controlled by the new configuration switch +`gsl_FEATURE_GSL_COMPATIBILITY_MODE`, which is is disabled by default and can be enabled by defining `gsl_FEATURE_GSL_COMPATIBILITY_MODE=1`. +**Default is 0.** + +If the GSL compatibility mode is enabled, *gsl-lite* additionally makes the following global definitions: +```c++ +namespace gsl = ::gsl_lite; +#define Expects( x ) gsl_Expects( x ) +#define Ensures( x ) gsl_Ensures( x ) +``` + +The GSL compatibility mode precludes the use of *gsl-lite* and Microsoft GSL in the same translation unit. Therefore, when making use of *gsl-lite* +in a public header file of a library, the GSL compatibility mode should not be enabled. + +The GSL compatibility mode causes no link-time interference between *gsl-lite* and as Microsoft GSL. Both libraries may be used in the same project as +long as no translation unit includes both at the same time. + +The legacy header file `<gsl/gsl-lite.hpp>` now forwards to `<gsl-lite/gsl-lite.hpp>` and implicitly enables the GSL compatibility mode. When the legacy +header is included, it emits a warning message which urges to either migrate to header `<gsl-lite/gsl-lite.hpp>`, namespace `gsl_lite` and the prefixed +contract checking macros `gsl_Expects()` and `gsl_Ensures()`, or to explicitly request GSL compatibility by defining `gsl_FEATURE_GSL_COMPATIBILITY_MODE=1`. + +#### `gsl_FEATURE_EXPERIMENTAL_RETURN_GUARD=0` +Provide experimental resource management helper functions [`on_return()` and `on_error()`](#ad-hoc-resource-management-c11-and-higher). +**Default is 0.** + +#### `gsl_FEATURE_STRING_SPAN=0` +String spans and related functionality are no longer part of the GSL specification. If the macro `gsl_FEATURE_STRING_SPAN` is set to 1, *gsl-lite* +continues to provide an implementation of the class `basic_string_span<>` along with the aliases `string_span`, `cstring_span`, `wstring_span`, `cwstring_span`, +the deprecated class `basic_zstring_span<>` with the aliases `zstring_span`, `czstring_span`, `wzstring_span`, `cwzstring_span`, and related classes and +functions such as `to_string()`, and `ensure_z()`. +**Default is 0.** + +#### `gsl_FEATURE_BYTE=0` +The `byte` type has been superseded by [`std::byte`](https://en.cppreference.com/w/cpp/types/byte) in C++17 and thus is no longer part of the GSL specification. +If the macro `gsl_FEATURE_BYTE` is set to 1, *gsl-lite* continues to provide an implementation of `byte` and related functions such as `as_bytes()`, `to_byte()`, +`as_bytes()`, and `as_writable_bytes()`. +**Default is 0.** + +#### `gsl_FEATURE_WITH_CONTAINER_TO_STD=0` +Define this to the highest C++ standard (98, 3, 11, 14, 17, 20) you want to include tagged-construction via `with_container`, or 0 to disable the feature. +**Default is 0.** + +#### `gsl_FEATURE_MAKE_SPAN_TO_STD=99` +Define this to the highest C++ standard (98, 3, 11, 14, 17, 20) you want to include `make_span()` creator functions, or 0 to disable the feature. +**Default is 99 for inclusion with any standard.** + +#### `gsl_FEATURE_BYTE_SPAN_TO_STD=99` +Define this to the highest C++ standard (98, 3, 11, 14, 17, 20) you want to include `byte_span()` creator functions, or 0 to disable the feature. +**Default is 99 for inclusion with any standard.** + + +### Other configuration macros + +#### `gsl_CONFIG_ACKNOWLEDGE_NONSTANDARD_ABI=0` +Define this to 1 to explicitly acknowledge that you are using *gsl-lite* with a non-standard ABI and that you control the build flags of all components linked into your target. +**Default is 0.** + +#### `gsl_api` + +Functions in *gsl-lite* are decorated with `gsl_api` where appropriate. Define this macro to specify your own function decoration. +**By default `gsl_api` is defined empty for non-CUDA platforms and `__host__ __device__` for the CUDA platform.** + +*Note:* When a custom `gsl_api` macro is defined, *gsl-lite* emits a warning to notify the programmer that this alters the binary interface of *gsl-lite*, leading to possible ODR violations. +The warning can be explicitly overridden by defining `gsl_CONFIG_ACKNOWLEDGE_NONSTANDARD_ABI=1`. + +#### `gsl_CONFIG_DEFAULTS_VERSION=1` +Define this macro to 0 to revert the default configuration to that of *gsl-lite* v0.\*. Cf. [Configuration changes](#configuration-changes) for a comprehensive list of configuration +values affected by this switch. +**Default is 1 for version-1 defaults.** + +*Note:* Defining `gsl_CONFIG_DEFAULTS_VERSION=0` changes the default value of [`gsl_CONFIG_INDEX_TYPE`](#gsl_config_index_typestdptrdiff_t). +This makes *gsl-lite* emit a warning to notify the programmer that this alters the binary interface of *gsl-lite*, leading to possible ODR violations. +The warning can be explicitly overridden by defining `gsl_CONFIG_ACKNOWLEDGE_NONSTANDARD_ABI=1`. + +#### `gsl_CPLUSPLUS` +Define this macro to override the auto-detection of the supported C++ standard if your compiler does not set the `__cplusplus` macro correctly. + +#### `gsl_CONFIG_DEPRECATE_TO_LEVEL=9` +Define this to and including the level you want deprecation; see table [Deprecated features](#deprecated-features) below. +**Default is 9.** + +#### `gsl_CONFIG_SPAN_INDEX_TYPE=std::size_t` +Define this macro to the type to use for indices in `span<>` and `basic_string_span<>`. +**Default is `std::size_t`.** + +*Note:* When a custom span index type is defined, *gsl-lite* emits a warning to notify the programmer that this alters the binary interface of *gsl-lite*, leading to possible ODR violations. +The warning can be explicitly overridden by defining `gsl_CONFIG_ACKNOWLEDGE_NONSTANDARD_ABI=1`. + +#### `gsl_CONFIG_INDEX_TYPE=std::ptrdiff_t` +Define this macro to the type to use for `gsl_lite::index`, `gsl_lite::dim`, `gsl_lite::stride`, and `gsl_lite::diff`. +**Default is `std::ptrdiff_t`.** + +*Note:* When a custom index type is defined, *gsl-lite* emits a warning to notify the programmer that this alters the binary interface of *gsl-lite*, leading to possible ODR violations. +The warning can be explicitly overridden by defining `gsl_CONFIG_ACKNOWLEDGE_NONSTANDARD_ABI=1`. + +#### `gsl_CONFIG_NOT_NULL_EXPLICIT_CTOR=1` +Define this macro to 0 to make `not_null<>`'s constructor implicit. +**Default is 1.** + +Preferably, rather than defining this macro to 0, use [`not_null_ic<>`](#not_null_icp) if you desire implicit construction. + +#### `gsl_CONFIG_TRANSPARENT_NOT_NULL=1` +If this macro is defined to 1, `not_null<>` supports typical member functions of the underlying smart pointer transparently (currently `get()`), while adding precondition checks. +This is conformant behavior but may be incompatible with older code which expects that `not_null<>::get()` returns the underlying pointer itself. +**Default is 1.** + +#### `gsl_CONFIG_NOT_NULL_GET_BY_CONST_REF=0` +Define this macro to 1 to have the legacy non-transparent version of `not_null<>::get()` return `T const &` instead of `T`. This may improve performance with types that have an expensive copy-constructor. +This macro must not be defined if `gsl_CONFIG_TRANSPARENT_NOT_NULL` is 1. +**Default is 0 for `T`.** + +#### `gsl_CONFIG_ALLOWS_SPAN_COMPARISON=0` +Define this macro to 1 to support equality comparison and relational comparison of spans. C++20 `std::span<>` does not support comparison because semantics (deep vs. shallow) are unclear. +**Default is 0.** + +#### `gsl_CONFIG_ALLOWS_NONSTRICT_SPAN_COMPARISON=0` +Define this macro to 1 to support equality comparison and relational comparison of spans of different types, e.g. of different const-volatile-ness. To be able to compare a string_span with a cstring_span, non-strict span comparison must be available. +**Default is 0.** + +#### `gsl_CONFIG_ALLOWS_UNCONSTRAINED_SPAN_CONTAINER_CTOR=0` +Define this macro to 1 to add the unconstrained span constructor for containers for pre-C++11 compilers that cannot constrain the constructor. This constructor may prove too greedy and interfere with other constructors. +**Default is 0.** + +*Note:* An alternative is to use the constructor tagged `with_container`: `span<V> s(gsl_lite::with_container, cont)`. + +#### `gsl_CONFIG_NARROW_THROWS_ON_TRUNCATION=1` +If this macro is 1, `narrow<>()` always throws a `narrowing_error` exception if the narrowing conversion loses information due to truncation. +If `gsl_CONFIG_NARROW_THROWS_ON_TRUNCATION` is 0 and `gsl_CONFIG_CONTRACT_VIOLATION_THROWS` is not defined, `narrow<>()` instead terminates on +information loss (using `std::terminate()` if available and a trap instruction otherwise, e.g. for CUDA device code). +**Default is 1.** + +*Note:* When `gsl_CONFIG_NARROW_THROWS_ON_TRUNCATION` is defined as 0, *gsl-lite* emits a warning to notify the programmer that this may lead to possible ODR violations. +The warning can be explicitly overridden by defining `gsl_CONFIG_ACKNOWLEDGE_NONSTANDARD_ABI=1`. + +#### `gsl_CONFIG_CONFIRMS_COMPILATION_ERRORS=0` +Define this macro to 1 to experience the by-design compile-time errors of the GSL components in the test suite. +**Default is 0.** + + +## Configuration changes, deprecated and removed features + +- [Configuration changes](#configuration-changes) +- [Deprecated features](#deprecated-features) +- [Removed features](#removed-features) + +### Configuration changes + +*gsl-lite* v1.0 changed the default values for several configuration options and switches: + + - [`gsl_FEATURE_STRING_SPAN`](#gsl_feature_string_span0): + Version-1 default: `gsl_FEATURE_STRING_SPAN=0` + Version-0 default: `gsl_FEATURE_STRING_SPAN=1` + Reason: string spans are no longer part of the GSL specification. + + - [`gsl_FEATURE_BYTE`](#gsl_feature_byte0): + Version-1 default: `gsl_FEATURE_BYTE=0` + Version-0 default: `gsl_FEATURE_BYTE=1` + Reason: `byte` has been superseded by [`std::byte`](https://en.cppreference.com/w/cpp/types/byte) in C++17. + + - [`gsl_CONFIG_DEPRECATE_TO_LEVEL`](#gsl_config_deprecate_to_level9): + Version-1 default: `gsl_CONFIG_DEPRECATE_TO_LEVEL=9` + Version-0 default: `gsl_CONFIG_DEPRECATE_TO_LEVEL=0` + + - [`gsl_CONFIG_INDEX_TYPE`](#gsl_config_index_typestdptrdiff_t): + Version-1 default: `std::ptrdiff_t` + Version-0 default: `gsl_CONFIG_SPAN_INDEX_TYPE` (defaults to `std::size_t`) + Reason: the GSL specifies `gsl_lite::index` to be a signed type. + + - [`gsl_CONFIG_ALLOWS_SPAN_COMPARISON`](#gsl_config_allows_span_comparison0): + Version-1 default: `gsl_CONFIG_ALLOWS_SPAN_COMPARISON=0` + Version-0 default: `gsl_CONFIG_ALLOWS_SPAN_COMPARISON=1` + Reason: C++20 `std::span<>` does not support comparison because semantics (deep vs. shallow) are unclear. + + - [`gsl_CONFIG_NOT_NULL_EXPLICIT_CTOR`](#gsl_config_not_null_explicit_ctor1): + Version-1 default: `gsl_CONFIG_NOT_NULL_EXPLICIT_CTOR=1` + Version-0 default: `gsl_CONFIG_NOT_NULL_EXPLICIT_CTOR=0` + Reason: see [M-GSL/#395](https://github.com/Microsoft/GSL/issues/395). (Note that `not_null<>` in Microsoft GSL has an implicit + constructor, cf. [M-GSL/#699](https://github.com/Microsoft/GSL/issues/699).) + + - [`gsl_CONFIG_TRANSPARENT_NOT_NULL`](#gsl_config_transparent_not_null1): + Version-1 default: `gsl_CONFIG_TRANSPARENT_NOT_NULL=1` + Version-0 default: `gsl_CONFIG_TRANSPARENT_NOT_NULL=0` + Reason: enables conformant behavior for `not_null<>::get()`. + + - [`gsl_CONFIG_NARROW_THROWS_ON_TRUNCATION`](#gsl_config_narrow_throws_on_truncation1): + Version-1 default: `gsl_CONFIG_NARROW_THROWS_ON_TRUNCATION=1` + Version-0 default: `gsl_CONFIG_NARROW_THROWS_ON_TRUNCATION=0` + Reason: enables conformant behavior for `narrow<>()` (cf. [#52](https://github.com/gsl-lite/gsl-lite/issues/52)). + + - [default runtime contract violation handling](#contract-checking-configuration-macros): + Version-1 default: `gsl_CONFIG_CONTRACT_VIOLATION_ASSERTS` + Version-0 default: `gsl_CONFIG_CONTRACT_VIOLATION_TERMINATES` + Reason: the mode enabled by `gsl_CONFIG_CONTRACT_VIOLATION_ASSERTS` is consistent with the behavior of the `assert()` macro + while retaining runtime contract checks even if `NDEBUG` is defined. + + +### Deprecated features + +The following features are deprecated since the indicated version. See macro [`gsl_CONFIG_DEPRECATE_TO_LEVEL`](#gsl_config_deprecate_to_level9) on how to control deprecation using the indicated level. + +Version | Level | Feature / Notes | +-------:|:-----:|:----------------| + 1.0.0 | 9 | `span<>::as_span<>()` (unsafe) | +0.41.0 | 7 | `basic_string_span<>`, `basic_zstring_span<>` and related aliases<br>(no longer part of the C++ Core Guidelines specification) | +0.35.0 | - | `gsl_CONFIG_CONTRACT_LEVEL_ON`, `gsl_CONFIG_CONTRACT_LEVEL_OFF`, `gsl_CONFIG_CONTRACT_LEVEL_EXPECTS_ONLY` and `gsl_CONFIG_CONTRACT_LEVEL_ENSURES_ONLY`<br>(use `gsl_CONFIG_CONTRACT_CHECKING_ON`, `gsl_CONFIG_CONTRACT_CHECKING_OFF`, &nbs;`gsl_CONFIG_CONTRACT_CHECKING_ENSURES_OFF`, `gsl_CONFIG_CONTRACT_CHECKING_EXPECTS_OFF` instead) | +0.7.0 | - | `gsl_CONFIG_ALLOWS_SPAN_CONTAINER_CTOR`<br>(use `gsl_CONFIG_ALLOWS_UNCONSTRAINED_SPAN_CONTAINER_CTOR` instead,<br>or consider `span(with_container, cont)`) | + + +### Removed features + +The following features are removed since the indicated version. + +Version | Feature / Notes | +-------:|:----------------| +1.0.0 | `finally()`, `on_return()`, and `on_error()` for pre-C++11 | + | `Owner()` and `implicit` macros | + | `basic_string_span<>`, `basic_zstring_span<>` and related aliases | + | `as_writeable_bytes()`, call indexing for spans, and `span::at()` | + | `span( std::nullptr_t, index_type )`<br>(`span( pointer, index_type )` is called instead) | + | `span( U *, index_type )`<br>(`span( pointer, index_type )` is called instead) | + | `span( std::shared_ptr<T> const & p )` | + | `span( std::unique_ptr<T> const & p )` | + | `span<>::length()`<br>(use `span<>::size()` instead) | + | `span<>::length_bytes()`<br>(use `span<>::size_bytes()` instead) | + | `span<>::as_bytes()`, `span<>::as_writeable_bytes()` | diff --git a/thirdparty/gsl-lite/example/01-basic.cpp b/thirdparty/gsl-lite/example/01-basic.cpp new file mode 100644 index 000000000..a593453f0 --- /dev/null +++ b/thirdparty/gsl-lite/example/01-basic.cpp @@ -0,0 +1,34 @@ + +#include <gsl-lite/gsl-lite.hpp> + +using namespace gsl_lite; + +int * use( not_null<int *> p ) +{ + // use p knowing it's not nullptr, NULL or 0. + + return p; +} + +struct Widget +{ + Widget() : owned_ptr( new int(42) ) {} + + ~Widget() { delete owned_ptr; } + + void work() { non_owned_ptr = use( make_not_null( owned_ptr ) ); } + +#if gsl_HAVE( ALIAS_TEMPLATE ) + owner<int *> owned_ptr; // if alias template support +#else // ! gsl_HAVE( ALIAS_TEMPLATE ) + int * owned_ptr; // otherwise +#endif // gsl_HAVE( ALIAS_TEMPLATE ) + + int * non_owned_ptr; +}; + +int main() +{ + Widget w; + w.work(); +} diff --git a/thirdparty/gsl-lite/example/02-span.cpp b/thirdparty/gsl-lite/example/02-span.cpp new file mode 100644 index 000000000..7bba66060 --- /dev/null +++ b/thirdparty/gsl-lite/example/02-span.cpp @@ -0,0 +1,65 @@ +// Use span + +#include <array> +#include <vector> +#include <iostream> + +#include <gsl-lite/gsl-lite.hpp> + +using namespace gsl_lite; + +int line = 0; + +void bad( int * arr, size_t num ) +{ + std::cout << ++line << ": "; + for ( size_t i = 0; i != num; ++i ) + { + std::cout << (i==0 ? "[":"") << arr[i] << (i!=num-1 ? ", ":"]\n"); + } +} + +void good( span<int> arr ) +{ + std::cout << ++line << ": "; + for ( size_t i = 0; i != arr.size(); ++i ) + { + std::cout << (i==0 ? "[":"") << arr[i] << (i!=arr.size()-1 ? ", ":"]\n"); + } +} + +int main() +{ + int arr[] = { 1, 2, 3, 4, 5, }; + + good( arr ); // 1. Good: deduce length + +#if gsl_CPP11_OR_GREATER + std::array<int, 6> ary = { 1, 2, 3, 4, 5, 6, }; + std::vector<int> vec = { 1, 2, 3, 4, 5, 6, 7, }; + + good( ary ); // 2. Good: single function handles + good( vec ); // 3. C-array, std::array and containers such as std::vector +#else + line += 2; +#endif + + bad( arr, gsl_DIMENSION_OF(arr) ); // 4. Avoid: specify elements and length separately + bad( arr, 3 ); // 5. Avoid, but not wrong + bad( arr, 7 ); // 6. Wrong, array length exceeded + +#if gsl_CPP11_OR_GREATER + good( { arr, 3 } ); // 7. Avoid, but not wrong + good( { arr, 7 } ); // 8. Wrong, array length exceeded +#else + good( span<int>( arr, 3 ) ); // 7. Avoid, but not wrong + good( span<int>( arr, 7 ) ); // 8. Wrong, array length exceeded +#endif + + span<int> s( arr ); + good( s.first ( 3 ) ); // 9. Fine + good( s.last ( 3 ) ); // 10. Fine + good( s.subspan( 1 ) ); // 11. Fine + good( s.subspan( 1, 3 ) ); // 12. Fine + good( s.subspan( 1, 5 ) ); // 13. Run-time error, terminate +} diff --git a/thirdparty/gsl-lite/example/with-CPM/README.md b/thirdparty/gsl-lite/example/with-CPM/README.md new file mode 100644 index 000000000..06e6f55b2 --- /dev/null +++ b/thirdparty/gsl-lite/example/with-CPM/README.md @@ -0,0 +1,30 @@ +# gsl-lite example project (CPM) + + +This is a simple CMake project that demonstrates how to use *gsl-lite* with the [CPM](https://github.com/cpm-cmake/CPM.cmake) package manager. + +Requirements: + +- [CMake](https://cmake.org/) 3.20 or newer must be in the path. +- A C++ compiler must be installed and available in the path. +- An internet connection must be available to allow CPM to retrieve the *gsl-lite* dependency from GitHub. + +To set up the project, open a command-line window, navigate to the directory containing this readme, and execute the following commands: + + +## Configure +``` +cmake --preset default +``` + + +## Build +``` +cmake --build build/default --config Debug +``` + +## Run + +| Windows | Linux, MacOS | +|----------------------------------|------------------------------------| +| `build\default\Debug\my-program` | `./build/default/Debug/my-program` | diff --git a/thirdparty/gsl-lite/example/with-CPM/cmake/CPM.cmake b/thirdparty/gsl-lite/example/with-CPM/cmake/CPM.cmake new file mode 100644 index 000000000..eea292118 --- /dev/null +++ b/thirdparty/gsl-lite/example/with-CPM/cmake/CPM.cmake @@ -0,0 +1,1291 @@ +# CPM.cmake - CMake's missing package manager +# =========================================== +# See https://github.com/cpm-cmake/CPM.cmake for usage and update instructions. +# +# MIT License +# ----------- +#[[ + Copyright (c) 2019-2023 Lars Melchior and contributors + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +]] + +cmake_minimum_required(VERSION 3.14 FATAL_ERROR) + +# Initialize logging prefix +if(NOT CPM_INDENT) + set(CPM_INDENT + "CPM:" + CACHE INTERNAL "" + ) +endif() + +if(NOT COMMAND cpm_message) + function(cpm_message) + message(${ARGV}) + endfunction() +endif() + +if(DEFINED EXTRACTED_CPM_VERSION) + set(CURRENT_CPM_VERSION "${EXTRACTED_CPM_VERSION}${CPM_DEVELOPMENT}") +else() + set(CURRENT_CPM_VERSION 0.40.8) +endif() + +get_filename_component(CPM_CURRENT_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}" REALPATH) +if(CPM_DIRECTORY) + if(NOT CPM_DIRECTORY STREQUAL CPM_CURRENT_DIRECTORY) + if(CPM_VERSION VERSION_LESS CURRENT_CPM_VERSION) + message( + AUTHOR_WARNING + "${CPM_INDENT} \ +A dependency is using a more recent CPM version (${CURRENT_CPM_VERSION}) than the current project (${CPM_VERSION}). \ +It is recommended to upgrade CPM to the most recent version. \ +See https://github.com/cpm-cmake/CPM.cmake for more information." + ) + endif() + if(${CMAKE_VERSION} VERSION_LESS "3.17.0") + include(FetchContent) + endif() + return() + endif() + + get_property( + CPM_INITIALIZED GLOBAL "" + PROPERTY CPM_INITIALIZED + SET + ) + if(CPM_INITIALIZED) + return() + endif() +endif() + +if(CURRENT_CPM_VERSION MATCHES "development-version") + message( + WARNING "${CPM_INDENT} Your project is using an unstable development version of CPM.cmake. \ +Please update to a recent release if possible. \ +See https://github.com/cpm-cmake/CPM.cmake for details." + ) +endif() + +set_property(GLOBAL PROPERTY CPM_INITIALIZED true) + +macro(cpm_set_policies) + # the policy allows us to change options without caching + cmake_policy(SET CMP0077 NEW) + set(CMAKE_POLICY_DEFAULT_CMP0077 NEW) + + # the policy allows us to change set(CACHE) without caching + if(POLICY CMP0126) + cmake_policy(SET CMP0126 NEW) + set(CMAKE_POLICY_DEFAULT_CMP0126 NEW) + endif() + + # The policy uses the download time for timestamp, instead of the timestamp in the archive. This + # allows for proper rebuilds when a projects url changes + if(POLICY CMP0135) + cmake_policy(SET CMP0135 NEW) + set(CMAKE_POLICY_DEFAULT_CMP0135 NEW) + endif() + + # treat relative git repository paths as being relative to the parent project's remote + if(POLICY CMP0150) + cmake_policy(SET CMP0150 NEW) + set(CMAKE_POLICY_DEFAULT_CMP0150 NEW) + endif() +endmacro() +cpm_set_policies() + +option(CPM_USE_LOCAL_PACKAGES "Always try to use `find_package` to get dependencies" + $ENV{CPM_USE_LOCAL_PACKAGES} +) +option(CPM_LOCAL_PACKAGES_ONLY "Only use `find_package` to get dependencies" + $ENV{CPM_LOCAL_PACKAGES_ONLY} +) +option(CPM_DOWNLOAD_ALL "Always download dependencies from source" $ENV{CPM_DOWNLOAD_ALL}) +option(CPM_DONT_UPDATE_MODULE_PATH "Don't update the module path to allow using find_package" + $ENV{CPM_DONT_UPDATE_MODULE_PATH} +) +option(CPM_DONT_CREATE_PACKAGE_LOCK "Don't create a package lock file in the binary path" + $ENV{CPM_DONT_CREATE_PACKAGE_LOCK} +) +option(CPM_INCLUDE_ALL_IN_PACKAGE_LOCK + "Add all packages added through CPM.cmake to the package lock" + $ENV{CPM_INCLUDE_ALL_IN_PACKAGE_LOCK} +) +option(CPM_USE_NAMED_CACHE_DIRECTORIES + "Use additional directory of package name in cache on the most nested level." + $ENV{CPM_USE_NAMED_CACHE_DIRECTORIES} +) + +set(CPM_VERSION + ${CURRENT_CPM_VERSION} + CACHE INTERNAL "" +) +set(CPM_DIRECTORY + ${CPM_CURRENT_DIRECTORY} + CACHE INTERNAL "" +) +set(CPM_FILE + ${CMAKE_CURRENT_LIST_FILE} + CACHE INTERNAL "" +) +set(CPM_PACKAGES + "" + CACHE INTERNAL "" +) +set(CPM_DRY_RUN + OFF + CACHE INTERNAL "Don't download or configure dependencies (for testing)" +) + +if(DEFINED ENV{CPM_SOURCE_CACHE}) + set(CPM_SOURCE_CACHE_DEFAULT $ENV{CPM_SOURCE_CACHE}) +else() + set(CPM_SOURCE_CACHE_DEFAULT OFF) +endif() + +set(CPM_SOURCE_CACHE + ${CPM_SOURCE_CACHE_DEFAULT} + CACHE PATH "Directory to download CPM dependencies" +) + +if(NOT CPM_DONT_UPDATE_MODULE_PATH AND NOT DEFINED CMAKE_FIND_PACKAGE_REDIRECTS_DIR) + set(CPM_MODULE_PATH + "${CMAKE_BINARY_DIR}/CPM_modules" + CACHE INTERNAL "" + ) + # remove old modules + file(REMOVE_RECURSE ${CPM_MODULE_PATH}) + file(MAKE_DIRECTORY ${CPM_MODULE_PATH}) + # locally added CPM modules should override global packages + set(CMAKE_MODULE_PATH "${CPM_MODULE_PATH};${CMAKE_MODULE_PATH}") +endif() + +if(NOT CPM_DONT_CREATE_PACKAGE_LOCK) + set(CPM_PACKAGE_LOCK_FILE + "${CMAKE_BINARY_DIR}/cpm-package-lock.cmake" + CACHE INTERNAL "" + ) + file(WRITE ${CPM_PACKAGE_LOCK_FILE} + "# CPM Package Lock\n# This file should be committed to version control\n\n" + ) +endif() + +include(FetchContent) + +# Try to infer package name from git repository uri (path or url) +function(cpm_package_name_from_git_uri URI RESULT) + if("${URI}" MATCHES "([^/:]+)/?.git/?$") + set(${RESULT} + ${CMAKE_MATCH_1} + PARENT_SCOPE + ) + else() + unset(${RESULT} PARENT_SCOPE) + endif() +endfunction() + +# Try to infer package name and version from a url +function(cpm_package_name_and_ver_from_url url outName outVer) + if(url MATCHES "[/\\?]([a-zA-Z0-9_\\.-]+)\\.(tar|tar\\.gz|tar\\.bz2|zip|ZIP)(\\?|/|$)") + # We matched an archive + set(filename "${CMAKE_MATCH_1}") + + if(filename MATCHES "([a-zA-Z0-9_\\.-]+)[_-]v?(([0-9]+\\.)*[0-9]+[a-zA-Z0-9]*)") + # We matched <name>-<version> (ie foo-1.2.3) + set(${outName} + "${CMAKE_MATCH_1}" + PARENT_SCOPE + ) + set(${outVer} + "${CMAKE_MATCH_2}" + PARENT_SCOPE + ) + elseif(filename MATCHES "(([0-9]+\\.)+[0-9]+[a-zA-Z0-9]*)") + # We couldn't find a name, but we found a version + # + # In many cases (which we don't handle here) the url would look something like + # `irrelevant/ACTUAL_PACKAGE_NAME/irrelevant/1.2.3.zip`. In such a case we can't possibly + # distinguish the package name from the irrelevant bits. Moreover if we try to match the + # package name from the filename, we'd get bogus at best. + unset(${outName} PARENT_SCOPE) + set(${outVer} + "${CMAKE_MATCH_1}" + PARENT_SCOPE + ) + else() + # Boldly assume that the file name is the package name. + # + # Yes, something like `irrelevant/ACTUAL_NAME/irrelevant/download.zip` will ruin our day, but + # such cases should be quite rare. No popular service does this... we think. + set(${outName} + "${filename}" + PARENT_SCOPE + ) + unset(${outVer} PARENT_SCOPE) + endif() + else() + # No ideas yet what to do with non-archives + unset(${outName} PARENT_SCOPE) + unset(${outVer} PARENT_SCOPE) + endif() +endfunction() + +function(cpm_find_package NAME VERSION) + string(REPLACE " " ";" EXTRA_ARGS "${ARGN}") + find_package(${NAME} ${VERSION} ${EXTRA_ARGS} QUIET) + if(${CPM_ARGS_NAME}_FOUND) + if(DEFINED ${CPM_ARGS_NAME}_VERSION) + set(VERSION ${${CPM_ARGS_NAME}_VERSION}) + endif() + cpm_message(STATUS "${CPM_INDENT} Using local package ${CPM_ARGS_NAME}@${VERSION}") + CPMRegisterPackage(${CPM_ARGS_NAME} "${VERSION}") + set(CPM_PACKAGE_FOUND + YES + PARENT_SCOPE + ) + else() + set(CPM_PACKAGE_FOUND + NO + PARENT_SCOPE + ) + endif() +endfunction() + +# Create a custom FindXXX.cmake module for a CPM package This prevents `find_package(NAME)` from +# finding the system library +function(cpm_create_module_file Name) + if(NOT CPM_DONT_UPDATE_MODULE_PATH) + if(DEFINED CMAKE_FIND_PACKAGE_REDIRECTS_DIR) + # Redirect find_package calls to the CPM package. This is what FetchContent does when you set + # OVERRIDE_FIND_PACKAGE. The CMAKE_FIND_PACKAGE_REDIRECTS_DIR works for find_package in CONFIG + # mode, unlike the Find${Name}.cmake fallback. CMAKE_FIND_PACKAGE_REDIRECTS_DIR is not defined + # in script mode, or in CMake < 3.24. + # https://cmake.org/cmake/help/latest/module/FetchContent.html#fetchcontent-find-package-integration-examples + string(TOLOWER ${Name} NameLower) + file(WRITE ${CMAKE_FIND_PACKAGE_REDIRECTS_DIR}/${NameLower}-config.cmake + "include(\"\${CMAKE_CURRENT_LIST_DIR}/${NameLower}-extra.cmake\" OPTIONAL)\n" + "include(\"\${CMAKE_CURRENT_LIST_DIR}/${Name}Extra.cmake\" OPTIONAL)\n" + ) + file(WRITE ${CMAKE_FIND_PACKAGE_REDIRECTS_DIR}/${NameLower}-config-version.cmake + "set(PACKAGE_VERSION_COMPATIBLE TRUE)\n" "set(PACKAGE_VERSION_EXACT TRUE)\n" + ) + else() + file(WRITE ${CPM_MODULE_PATH}/Find${Name}.cmake + "include(\"${CPM_FILE}\")\n${ARGN}\nset(${Name}_FOUND TRUE)" + ) + endif() + endif() +endfunction() + +# Find a package locally or fallback to CPMAddPackage +function(CPMFindPackage) + set(oneValueArgs NAME VERSION GIT_TAG FIND_PACKAGE_ARGUMENTS) + + cmake_parse_arguments(CPM_ARGS "" "${oneValueArgs}" "" ${ARGN}) + + if(NOT DEFINED CPM_ARGS_VERSION) + if(DEFINED CPM_ARGS_GIT_TAG) + cpm_get_version_from_git_tag("${CPM_ARGS_GIT_TAG}" CPM_ARGS_VERSION) + endif() + endif() + + set(downloadPackage ${CPM_DOWNLOAD_ALL}) + if(DEFINED CPM_DOWNLOAD_${CPM_ARGS_NAME}) + set(downloadPackage ${CPM_DOWNLOAD_${CPM_ARGS_NAME}}) + elseif(DEFINED ENV{CPM_DOWNLOAD_${CPM_ARGS_NAME}}) + set(downloadPackage $ENV{CPM_DOWNLOAD_${CPM_ARGS_NAME}}) + endif() + if(downloadPackage) + CPMAddPackage(${ARGN}) + cpm_export_variables(${CPM_ARGS_NAME}) + return() + endif() + + cpm_find_package(${CPM_ARGS_NAME} "${CPM_ARGS_VERSION}" ${CPM_ARGS_FIND_PACKAGE_ARGUMENTS}) + + if(NOT CPM_PACKAGE_FOUND) + CPMAddPackage(${ARGN}) + cpm_export_variables(${CPM_ARGS_NAME}) + endif() + +endfunction() + +# checks if a package has been added before +function(cpm_check_if_package_already_added CPM_ARGS_NAME CPM_ARGS_VERSION) + if("${CPM_ARGS_NAME}" IN_LIST CPM_PACKAGES) + CPMGetPackageVersion(${CPM_ARGS_NAME} CPM_PACKAGE_VERSION) + if("${CPM_PACKAGE_VERSION}" VERSION_LESS "${CPM_ARGS_VERSION}") + message( + WARNING + "${CPM_INDENT} Requires a newer version of ${CPM_ARGS_NAME} (${CPM_ARGS_VERSION}) than currently included (${CPM_PACKAGE_VERSION})." + ) + endif() + cpm_get_fetch_properties(${CPM_ARGS_NAME}) + set(${CPM_ARGS_NAME}_ADDED NO) + set(CPM_PACKAGE_ALREADY_ADDED + YES + PARENT_SCOPE + ) + cpm_export_variables(${CPM_ARGS_NAME}) + else() + set(CPM_PACKAGE_ALREADY_ADDED + NO + PARENT_SCOPE + ) + endif() +endfunction() + +# Parse the argument of CPMAddPackage in case a single one was provided and convert it to a list of +# arguments which can then be parsed idiomatically. For example gh:foo/[email protected] will be converted +# to: GITHUB_REPOSITORY;foo/bar;VERSION;1.2.3 +function(cpm_parse_add_package_single_arg arg outArgs) + # Look for a scheme + if("${arg}" MATCHES "^([a-zA-Z]+):(.+)$") + string(TOLOWER "${CMAKE_MATCH_1}" scheme) + set(uri "${CMAKE_MATCH_2}") + + # Check for CPM-specific schemes + if(scheme STREQUAL "gh") + set(out "GITHUB_REPOSITORY;${uri}") + set(packageType "git") + elseif(scheme STREQUAL "gl") + set(out "GITLAB_REPOSITORY;${uri}") + set(packageType "git") + elseif(scheme STREQUAL "bb") + set(out "BITBUCKET_REPOSITORY;${uri}") + set(packageType "git") + # A CPM-specific scheme was not found. Looks like this is a generic URL so try to determine + # type + elseif(arg MATCHES ".git/?(@|#|$)") + set(out "GIT_REPOSITORY;${arg}") + set(packageType "git") + else() + # Fall back to a URL + set(out "URL;${arg}") + set(packageType "archive") + + # We could also check for SVN since FetchContent supports it, but SVN is so rare these days. + # We just won't bother with the additional complexity it will induce in this function. SVN is + # done by multi-arg + endif() + else() + if(arg MATCHES ".git/?(@|#|$)") + set(out "GIT_REPOSITORY;${arg}") + set(packageType "git") + else() + # Give up + message(FATAL_ERROR "${CPM_INDENT} Can't determine package type of '${arg}'") + endif() + endif() + + # For all packages we interpret @... as version. Only replace the last occurrence. Thus URIs + # containing '@' can be used + string(REGEX REPLACE "@([^@]+)$" ";VERSION;\\1" out "${out}") + + # Parse the rest according to package type + if(packageType STREQUAL "git") + # For git repos we interpret #... as a tag or branch or commit hash + string(REGEX REPLACE "#([^#]+)$" ";GIT_TAG;\\1" out "${out}") + elseif(packageType STREQUAL "archive") + # For archives we interpret #... as a URL hash. + string(REGEX REPLACE "#([^#]+)$" ";URL_HASH;\\1" out "${out}") + # We don't try to parse the version if it's not provided explicitly. cpm_get_version_from_url + # should do this at a later point + else() + # We should never get here. This is an assertion and hitting it means there's a problem with the + # code above. A packageType was set, but not handled by this if-else. + message(FATAL_ERROR "${CPM_INDENT} Unsupported package type '${packageType}' of '${arg}'") + endif() + + set(${outArgs} + ${out} + PARENT_SCOPE + ) +endfunction() + +# Check that the working directory for a git repo is clean +function(cpm_check_git_working_dir_is_clean repoPath gitTag isClean) + + find_package(Git REQUIRED) + + if(NOT GIT_EXECUTABLE) + # No git executable, assume directory is clean + set(${isClean} + TRUE + PARENT_SCOPE + ) + return() + endif() + + # check for uncommitted changes + execute_process( + COMMAND ${GIT_EXECUTABLE} status --porcelain + RESULT_VARIABLE resultGitStatus + OUTPUT_VARIABLE repoStatus + OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_QUIET + WORKING_DIRECTORY ${repoPath} + ) + if(resultGitStatus) + # not supposed to happen, assume clean anyway + message(WARNING "${CPM_INDENT} Calling git status on folder ${repoPath} failed") + set(${isClean} + TRUE + PARENT_SCOPE + ) + return() + endif() + + if(NOT "${repoStatus}" STREQUAL "") + set(${isClean} + FALSE + PARENT_SCOPE + ) + return() + endif() + + # check for committed changes + execute_process( + COMMAND ${GIT_EXECUTABLE} diff -s --exit-code ${gitTag} + RESULT_VARIABLE resultGitDiff + OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_QUIET + WORKING_DIRECTORY ${repoPath} + ) + + if(${resultGitDiff} EQUAL 0) + set(${isClean} + TRUE + PARENT_SCOPE + ) + else() + set(${isClean} + FALSE + PARENT_SCOPE + ) + endif() + +endfunction() + +# Add PATCH_COMMAND to CPM_ARGS_UNPARSED_ARGUMENTS. This method consumes a list of files in ARGN +# then generates a `PATCH_COMMAND` appropriate for `ExternalProject_Add()`. This command is appended +# to the parent scope's `CPM_ARGS_UNPARSED_ARGUMENTS`. +function(cpm_add_patches) + # Return if no patch files are supplied. + if(NOT ARGN) + return() + endif() + + # Find the patch program. + find_program(PATCH_EXECUTABLE patch) + if(CMAKE_HOST_WIN32 AND NOT PATCH_EXECUTABLE) + # The Windows git executable is distributed with patch.exe. Find the path to the executable, if + # it exists, then search `../usr/bin` and `../../usr/bin` for patch.exe. + find_package(Git QUIET) + if(GIT_EXECUTABLE) + get_filename_component(extra_search_path ${GIT_EXECUTABLE} DIRECTORY) + get_filename_component(extra_search_path_1up ${extra_search_path} DIRECTORY) + get_filename_component(extra_search_path_2up ${extra_search_path_1up} DIRECTORY) + find_program( + PATCH_EXECUTABLE patch HINTS "${extra_search_path_1up}/usr/bin" + "${extra_search_path_2up}/usr/bin" + ) + endif() + endif() + if(NOT PATCH_EXECUTABLE) + message(FATAL_ERROR "Couldn't find `patch` executable to use with PATCHES keyword.") + endif() + + # Create a temporary + set(temp_list ${CPM_ARGS_UNPARSED_ARGUMENTS}) + + # Ensure each file exists (or error out) and add it to the list. + set(first_item True) + foreach(PATCH_FILE ${ARGN}) + # Make sure the patch file exists, if we can't find it, try again in the current directory. + if(NOT EXISTS "${PATCH_FILE}") + if(NOT EXISTS "${CMAKE_CURRENT_LIST_DIR}/${PATCH_FILE}") + message(FATAL_ERROR "Couldn't find patch file: '${PATCH_FILE}'") + endif() + set(PATCH_FILE "${CMAKE_CURRENT_LIST_DIR}/${PATCH_FILE}") + endif() + + # Convert to absolute path for use with patch file command. + get_filename_component(PATCH_FILE "${PATCH_FILE}" ABSOLUTE) + + # The first patch entry must be preceded by "PATCH_COMMAND" while the following items are + # preceded by "&&". + if(first_item) + set(first_item False) + list(APPEND temp_list "PATCH_COMMAND") + else() + list(APPEND temp_list "&&") + endif() + # Add the patch command to the list + list(APPEND temp_list "${PATCH_EXECUTABLE}" "-p1" "<" "${PATCH_FILE}") + endforeach() + + # Move temp out into parent scope. + set(CPM_ARGS_UNPARSED_ARGUMENTS + ${temp_list} + PARENT_SCOPE + ) + +endfunction() + +# method to overwrite internal FetchContent properties, to allow using CPM.cmake to overload +# FetchContent calls. As these are internal cmake properties, this method should be used carefully +# and may need modification in future CMake versions. Source: +# https://github.com/Kitware/CMake/blob/dc3d0b5a0a7d26d43d6cfeb511e224533b5d188f/Modules/FetchContent.cmake#L1152 +function(cpm_override_fetchcontent contentName) + cmake_parse_arguments(PARSE_ARGV 1 arg "" "SOURCE_DIR;BINARY_DIR" "") + if(NOT "${arg_UNPARSED_ARGUMENTS}" STREQUAL "") + message(FATAL_ERROR "${CPM_INDENT} Unsupported arguments: ${arg_UNPARSED_ARGUMENTS}") + endif() + + string(TOLOWER ${contentName} contentNameLower) + set(prefix "_FetchContent_${contentNameLower}") + + set(propertyName "${prefix}_sourceDir") + define_property( + GLOBAL + PROPERTY ${propertyName} + BRIEF_DOCS "Internal implementation detail of FetchContent_Populate()" + FULL_DOCS "Details used by FetchContent_Populate() for ${contentName}" + ) + set_property(GLOBAL PROPERTY ${propertyName} "${arg_SOURCE_DIR}") + + set(propertyName "${prefix}_binaryDir") + define_property( + GLOBAL + PROPERTY ${propertyName} + BRIEF_DOCS "Internal implementation detail of FetchContent_Populate()" + FULL_DOCS "Details used by FetchContent_Populate() for ${contentName}" + ) + set_property(GLOBAL PROPERTY ${propertyName} "${arg_BINARY_DIR}") + + set(propertyName "${prefix}_populated") + define_property( + GLOBAL + PROPERTY ${propertyName} + BRIEF_DOCS "Internal implementation detail of FetchContent_Populate()" + FULL_DOCS "Details used by FetchContent_Populate() for ${contentName}" + ) + set_property(GLOBAL PROPERTY ${propertyName} TRUE) +endfunction() + +# Download and add a package from source +function(CPMAddPackage) + cpm_set_policies() + + list(LENGTH ARGN argnLength) + if(argnLength EQUAL 1) + cpm_parse_add_package_single_arg("${ARGN}" ARGN) + + # The shorthand syntax implies EXCLUDE_FROM_ALL and SYSTEM + set(ARGN "${ARGN};EXCLUDE_FROM_ALL;YES;SYSTEM;YES;") + endif() + + set(oneValueArgs + NAME + FORCE + VERSION + GIT_TAG + DOWNLOAD_ONLY + GITHUB_REPOSITORY + GITLAB_REPOSITORY + BITBUCKET_REPOSITORY + GIT_REPOSITORY + SOURCE_DIR + FIND_PACKAGE_ARGUMENTS + NO_CACHE + SYSTEM + GIT_SHALLOW + EXCLUDE_FROM_ALL + SOURCE_SUBDIR + CUSTOM_CACHE_KEY + ) + + set(multiValueArgs URL OPTIONS DOWNLOAD_COMMAND PATCHES) + + cmake_parse_arguments(CPM_ARGS "" "${oneValueArgs}" "${multiValueArgs}" "${ARGN}") + + # Set default values for arguments + + if(NOT DEFINED CPM_ARGS_VERSION) + if(DEFINED CPM_ARGS_GIT_TAG) + cpm_get_version_from_git_tag("${CPM_ARGS_GIT_TAG}" CPM_ARGS_VERSION) + endif() + endif() + + if(CPM_ARGS_DOWNLOAD_ONLY) + set(DOWNLOAD_ONLY ${CPM_ARGS_DOWNLOAD_ONLY}) + else() + set(DOWNLOAD_ONLY NO) + endif() + + if(DEFINED CPM_ARGS_GITHUB_REPOSITORY) + set(CPM_ARGS_GIT_REPOSITORY "https://github.com/${CPM_ARGS_GITHUB_REPOSITORY}.git") + elseif(DEFINED CPM_ARGS_GITLAB_REPOSITORY) + set(CPM_ARGS_GIT_REPOSITORY "https://gitlab.com/${CPM_ARGS_GITLAB_REPOSITORY}.git") + elseif(DEFINED CPM_ARGS_BITBUCKET_REPOSITORY) + set(CPM_ARGS_GIT_REPOSITORY "https://bitbucket.org/${CPM_ARGS_BITBUCKET_REPOSITORY}.git") + endif() + + if(DEFINED CPM_ARGS_GIT_REPOSITORY) + list(APPEND CPM_ARGS_UNPARSED_ARGUMENTS GIT_REPOSITORY ${CPM_ARGS_GIT_REPOSITORY}) + if(NOT DEFINED CPM_ARGS_GIT_TAG) + set(CPM_ARGS_GIT_TAG v${CPM_ARGS_VERSION}) + endif() + + # If a name wasn't provided, try to infer it from the git repo + if(NOT DEFINED CPM_ARGS_NAME) + cpm_package_name_from_git_uri(${CPM_ARGS_GIT_REPOSITORY} CPM_ARGS_NAME) + endif() + endif() + + set(CPM_SKIP_FETCH FALSE) + + if(DEFINED CPM_ARGS_GIT_TAG) + list(APPEND CPM_ARGS_UNPARSED_ARGUMENTS GIT_TAG ${CPM_ARGS_GIT_TAG}) + # If GIT_SHALLOW is explicitly specified, honor the value. + if(DEFINED CPM_ARGS_GIT_SHALLOW) + list(APPEND CPM_ARGS_UNPARSED_ARGUMENTS GIT_SHALLOW ${CPM_ARGS_GIT_SHALLOW}) + endif() + endif() + + if(DEFINED CPM_ARGS_URL) + # If a name or version aren't provided, try to infer them from the URL + list(GET CPM_ARGS_URL 0 firstUrl) + cpm_package_name_and_ver_from_url(${firstUrl} nameFromUrl verFromUrl) + # If we fail to obtain name and version from the first URL, we could try other URLs if any. + # However multiple URLs are expected to be quite rare, so for now we won't bother. + + # If the caller provided their own name and version, they trump the inferred ones. + if(NOT DEFINED CPM_ARGS_NAME) + set(CPM_ARGS_NAME ${nameFromUrl}) + endif() + if(NOT DEFINED CPM_ARGS_VERSION) + set(CPM_ARGS_VERSION ${verFromUrl}) + endif() + + list(APPEND CPM_ARGS_UNPARSED_ARGUMENTS URL "${CPM_ARGS_URL}") + endif() + + # Check for required arguments + + if(NOT DEFINED CPM_ARGS_NAME) + message( + FATAL_ERROR + "${CPM_INDENT} 'NAME' was not provided and couldn't be automatically inferred for package added with arguments: '${ARGN}'" + ) + endif() + + # Check if package has been added before + cpm_check_if_package_already_added(${CPM_ARGS_NAME} "${CPM_ARGS_VERSION}") + if(CPM_PACKAGE_ALREADY_ADDED) + cpm_export_variables(${CPM_ARGS_NAME}) + return() + endif() + + # Check for manual overrides + if(NOT CPM_ARGS_FORCE AND NOT "${CPM_${CPM_ARGS_NAME}_SOURCE}" STREQUAL "") + set(PACKAGE_SOURCE ${CPM_${CPM_ARGS_NAME}_SOURCE}) + set(CPM_${CPM_ARGS_NAME}_SOURCE "") + CPMAddPackage( + NAME "${CPM_ARGS_NAME}" + SOURCE_DIR "${PACKAGE_SOURCE}" + EXCLUDE_FROM_ALL "${CPM_ARGS_EXCLUDE_FROM_ALL}" + SYSTEM "${CPM_ARGS_SYSTEM}" + PATCHES "${CPM_ARGS_PATCHES}" + OPTIONS "${CPM_ARGS_OPTIONS}" + SOURCE_SUBDIR "${CPM_ARGS_SOURCE_SUBDIR}" + DOWNLOAD_ONLY "${DOWNLOAD_ONLY}" + FORCE True + ) + cpm_export_variables(${CPM_ARGS_NAME}) + return() + endif() + + # Check for available declaration + if(NOT CPM_ARGS_FORCE AND NOT "${CPM_DECLARATION_${CPM_ARGS_NAME}}" STREQUAL "") + set(declaration ${CPM_DECLARATION_${CPM_ARGS_NAME}}) + set(CPM_DECLARATION_${CPM_ARGS_NAME} "") + CPMAddPackage(${declaration}) + cpm_export_variables(${CPM_ARGS_NAME}) + # checking again to ensure version and option compatibility + cpm_check_if_package_already_added(${CPM_ARGS_NAME} "${CPM_ARGS_VERSION}") + return() + endif() + + if(NOT CPM_ARGS_FORCE) + if(CPM_USE_LOCAL_PACKAGES OR CPM_LOCAL_PACKAGES_ONLY) + cpm_find_package(${CPM_ARGS_NAME} "${CPM_ARGS_VERSION}" ${CPM_ARGS_FIND_PACKAGE_ARGUMENTS}) + + if(CPM_PACKAGE_FOUND) + cpm_export_variables(${CPM_ARGS_NAME}) + return() + endif() + + if(CPM_LOCAL_PACKAGES_ONLY) + message( + SEND_ERROR + "${CPM_INDENT} ${CPM_ARGS_NAME} not found via find_package(${CPM_ARGS_NAME} ${CPM_ARGS_VERSION})" + ) + endif() + endif() + endif() + + CPMRegisterPackage("${CPM_ARGS_NAME}" "${CPM_ARGS_VERSION}") + + if(DEFINED CPM_ARGS_GIT_TAG) + set(PACKAGE_INFO "${CPM_ARGS_GIT_TAG}") + elseif(DEFINED CPM_ARGS_SOURCE_DIR) + set(PACKAGE_INFO "${CPM_ARGS_SOURCE_DIR}") + else() + set(PACKAGE_INFO "${CPM_ARGS_VERSION}") + endif() + + if(DEFINED FETCHCONTENT_BASE_DIR) + # respect user's FETCHCONTENT_BASE_DIR if set + set(CPM_FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR}) + else() + set(CPM_FETCHCONTENT_BASE_DIR ${CMAKE_BINARY_DIR}/_deps) + endif() + + cpm_add_patches(${CPM_ARGS_PATCHES}) + + if(DEFINED CPM_ARGS_DOWNLOAD_COMMAND) + list(APPEND CPM_ARGS_UNPARSED_ARGUMENTS DOWNLOAD_COMMAND ${CPM_ARGS_DOWNLOAD_COMMAND}) + elseif(DEFINED CPM_ARGS_SOURCE_DIR) + list(APPEND CPM_ARGS_UNPARSED_ARGUMENTS SOURCE_DIR ${CPM_ARGS_SOURCE_DIR}) + if(NOT IS_ABSOLUTE ${CPM_ARGS_SOURCE_DIR}) + # Expand `CPM_ARGS_SOURCE_DIR` relative path. This is important because EXISTS doesn't work + # for relative paths. + get_filename_component( + source_directory ${CPM_ARGS_SOURCE_DIR} REALPATH BASE_DIR ${CMAKE_CURRENT_BINARY_DIR} + ) + else() + set(source_directory ${CPM_ARGS_SOURCE_DIR}) + endif() + if(NOT EXISTS ${source_directory}) + string(TOLOWER ${CPM_ARGS_NAME} lower_case_name) + # remove timestamps so CMake will re-download the dependency + file(REMOVE_RECURSE "${CPM_FETCHCONTENT_BASE_DIR}/${lower_case_name}-subbuild") + endif() + elseif(CPM_SOURCE_CACHE AND NOT CPM_ARGS_NO_CACHE) + string(TOLOWER ${CPM_ARGS_NAME} lower_case_name) + set(origin_parameters ${CPM_ARGS_UNPARSED_ARGUMENTS}) + list(SORT origin_parameters) + if(CPM_ARGS_CUSTOM_CACHE_KEY) + # Application set a custom unique directory name + set(download_directory ${CPM_SOURCE_CACHE}/${lower_case_name}/${CPM_ARGS_CUSTOM_CACHE_KEY}) + elseif(CPM_USE_NAMED_CACHE_DIRECTORIES) + string(SHA1 origin_hash "${origin_parameters};NEW_CACHE_STRUCTURE_TAG") + set(download_directory ${CPM_SOURCE_CACHE}/${lower_case_name}/${origin_hash}/${CPM_ARGS_NAME}) + else() + string(SHA1 origin_hash "${origin_parameters}") + set(download_directory ${CPM_SOURCE_CACHE}/${lower_case_name}/${origin_hash}) + endif() + # Expand `download_directory` relative path. This is important because EXISTS doesn't work for + # relative paths. + get_filename_component(download_directory ${download_directory} ABSOLUTE) + list(APPEND CPM_ARGS_UNPARSED_ARGUMENTS SOURCE_DIR ${download_directory}) + + if(CPM_SOURCE_CACHE) + file(LOCK ${download_directory}/../cmake.lock) + endif() + + if(EXISTS ${download_directory}) + if(CPM_SOURCE_CACHE) + file(LOCK ${download_directory}/../cmake.lock RELEASE) + endif() + + cpm_store_fetch_properties( + ${CPM_ARGS_NAME} "${download_directory}" + "${CPM_FETCHCONTENT_BASE_DIR}/${lower_case_name}-build" + ) + cpm_get_fetch_properties("${CPM_ARGS_NAME}") + + if(DEFINED CPM_ARGS_GIT_TAG AND NOT (PATCH_COMMAND IN_LIST CPM_ARGS_UNPARSED_ARGUMENTS)) + # warn if cache has been changed since checkout + cpm_check_git_working_dir_is_clean(${download_directory} ${CPM_ARGS_GIT_TAG} IS_CLEAN) + if(NOT ${IS_CLEAN}) + message( + WARNING "${CPM_INDENT} Cache for ${CPM_ARGS_NAME} (${download_directory}) is dirty" + ) + endif() + endif() + + cpm_add_subdirectory( + "${CPM_ARGS_NAME}" + "${DOWNLOAD_ONLY}" + "${${CPM_ARGS_NAME}_SOURCE_DIR}/${CPM_ARGS_SOURCE_SUBDIR}" + "${${CPM_ARGS_NAME}_BINARY_DIR}" + "${CPM_ARGS_EXCLUDE_FROM_ALL}" + "${CPM_ARGS_SYSTEM}" + "${CPM_ARGS_OPTIONS}" + ) + set(PACKAGE_INFO "${PACKAGE_INFO} at ${download_directory}") + + # As the source dir is already cached/populated, we override the call to FetchContent. + set(CPM_SKIP_FETCH TRUE) + cpm_override_fetchcontent( + "${lower_case_name}" SOURCE_DIR "${${CPM_ARGS_NAME}_SOURCE_DIR}/${CPM_ARGS_SOURCE_SUBDIR}" + BINARY_DIR "${${CPM_ARGS_NAME}_BINARY_DIR}" + ) + + else() + # Enable shallow clone when GIT_TAG is not a commit hash. Our guess may not be accurate, but + # it should guarantee no commit hash get mis-detected. + if(NOT DEFINED CPM_ARGS_GIT_SHALLOW) + cpm_is_git_tag_commit_hash("${CPM_ARGS_GIT_TAG}" IS_HASH) + if(NOT ${IS_HASH}) + list(APPEND CPM_ARGS_UNPARSED_ARGUMENTS GIT_SHALLOW TRUE) + endif() + endif() + + # remove timestamps so CMake will re-download the dependency + file(REMOVE_RECURSE ${CPM_FETCHCONTENT_BASE_DIR}/${lower_case_name}-subbuild) + set(PACKAGE_INFO "${PACKAGE_INFO} to ${download_directory}") + endif() + endif() + + if(NOT "${DOWNLOAD_ONLY}") + cpm_create_module_file(${CPM_ARGS_NAME} "CPMAddPackage(\"${ARGN}\")") + endif() + + if(CPM_PACKAGE_LOCK_ENABLED) + if((CPM_ARGS_VERSION AND NOT CPM_ARGS_SOURCE_DIR) OR CPM_INCLUDE_ALL_IN_PACKAGE_LOCK) + cpm_add_to_package_lock(${CPM_ARGS_NAME} "${ARGN}") + elseif(CPM_ARGS_SOURCE_DIR) + cpm_add_comment_to_package_lock(${CPM_ARGS_NAME} "local directory") + else() + cpm_add_comment_to_package_lock(${CPM_ARGS_NAME} "${ARGN}") + endif() + endif() + + cpm_message( + STATUS "${CPM_INDENT} Adding package ${CPM_ARGS_NAME}@${CPM_ARGS_VERSION} (${PACKAGE_INFO})" + ) + + if(NOT CPM_SKIP_FETCH) + # CMake 3.28 added EXCLUDE, SYSTEM (3.25), and SOURCE_SUBDIR (3.18) to FetchContent_Declare. + # Calling FetchContent_MakeAvailable will then internally forward these options to + # add_subdirectory. Up until these changes, we had to call FetchContent_Populate and + # add_subdirectory separately, which is no longer necessary and has been deprecated as of 3.30. + # A Bug in CMake prevents us to use the non-deprecated functions until 3.30.3. + set(fetchContentDeclareExtraArgs "") + if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.30.3") + if(${CPM_ARGS_EXCLUDE_FROM_ALL}) + list(APPEND fetchContentDeclareExtraArgs EXCLUDE_FROM_ALL) + endif() + if(${CPM_ARGS_SYSTEM}) + list(APPEND fetchContentDeclareExtraArgs SYSTEM) + endif() + if(DEFINED CPM_ARGS_SOURCE_SUBDIR) + list(APPEND fetchContentDeclareExtraArgs SOURCE_SUBDIR ${CPM_ARGS_SOURCE_SUBDIR}) + endif() + # For CMake version <3.28 OPTIONS are parsed in cpm_add_subdirectory + if(CPM_ARGS_OPTIONS AND NOT DOWNLOAD_ONLY) + foreach(OPTION ${CPM_ARGS_OPTIONS}) + cpm_parse_option("${OPTION}") + set(${OPTION_KEY} "${OPTION_VALUE}") + endforeach() + endif() + endif() + cpm_declare_fetch( + "${CPM_ARGS_NAME}" ${fetchContentDeclareExtraArgs} "${CPM_ARGS_UNPARSED_ARGUMENTS}" + ) + + cpm_fetch_package("${CPM_ARGS_NAME}" ${DOWNLOAD_ONLY} populated ${CPM_ARGS_UNPARSED_ARGUMENTS}) + if(CPM_SOURCE_CACHE AND download_directory) + file(LOCK ${download_directory}/../cmake.lock RELEASE) + endif() + if(${populated} AND ${CMAKE_VERSION} VERSION_LESS "3.30.3") + cpm_add_subdirectory( + "${CPM_ARGS_NAME}" + "${DOWNLOAD_ONLY}" + "${${CPM_ARGS_NAME}_SOURCE_DIR}/${CPM_ARGS_SOURCE_SUBDIR}" + "${${CPM_ARGS_NAME}_BINARY_DIR}" + "${CPM_ARGS_EXCLUDE_FROM_ALL}" + "${CPM_ARGS_SYSTEM}" + "${CPM_ARGS_OPTIONS}" + ) + endif() + cpm_get_fetch_properties("${CPM_ARGS_NAME}") + endif() + + set(${CPM_ARGS_NAME}_ADDED YES) + cpm_export_variables("${CPM_ARGS_NAME}") +endfunction() + +# Fetch a previously declared package +macro(CPMGetPackage Name) + if(DEFINED "CPM_DECLARATION_${Name}") + CPMAddPackage(NAME ${Name}) + else() + message(SEND_ERROR "${CPM_INDENT} Cannot retrieve package ${Name}: no declaration available") + endif() +endmacro() + +# export variables available to the caller to the parent scope expects ${CPM_ARGS_NAME} to be set +macro(cpm_export_variables name) + set(${name}_SOURCE_DIR + "${${name}_SOURCE_DIR}" + PARENT_SCOPE + ) + set(${name}_BINARY_DIR + "${${name}_BINARY_DIR}" + PARENT_SCOPE + ) + set(${name}_ADDED + "${${name}_ADDED}" + PARENT_SCOPE + ) + set(CPM_LAST_PACKAGE_NAME + "${name}" + PARENT_SCOPE + ) +endmacro() + +# declares a package, so that any call to CPMAddPackage for the package name will use these +# arguments instead. Previous declarations will not be overridden. +macro(CPMDeclarePackage Name) + if(NOT DEFINED "CPM_DECLARATION_${Name}") + set("CPM_DECLARATION_${Name}" "${ARGN}") + endif() +endmacro() + +function(cpm_add_to_package_lock Name) + if(NOT CPM_DONT_CREATE_PACKAGE_LOCK) + cpm_prettify_package_arguments(PRETTY_ARGN false ${ARGN}) + file(APPEND ${CPM_PACKAGE_LOCK_FILE} "# ${Name}\nCPMDeclarePackage(${Name}\n${PRETTY_ARGN})\n") + endif() +endfunction() + +function(cpm_add_comment_to_package_lock Name) + if(NOT CPM_DONT_CREATE_PACKAGE_LOCK) + cpm_prettify_package_arguments(PRETTY_ARGN true ${ARGN}) + file(APPEND ${CPM_PACKAGE_LOCK_FILE} + "# ${Name} (unversioned)\n# CPMDeclarePackage(${Name}\n${PRETTY_ARGN}#)\n" + ) + endif() +endfunction() + +# includes the package lock file if it exists and creates a target `cpm-update-package-lock` to +# update it +macro(CPMUsePackageLock file) + if(NOT CPM_DONT_CREATE_PACKAGE_LOCK) + get_filename_component(CPM_ABSOLUTE_PACKAGE_LOCK_PATH ${file} ABSOLUTE) + if(EXISTS ${CPM_ABSOLUTE_PACKAGE_LOCK_PATH}) + include(${CPM_ABSOLUTE_PACKAGE_LOCK_PATH}) + endif() + if(NOT TARGET cpm-update-package-lock) + add_custom_target( + cpm-update-package-lock COMMAND ${CMAKE_COMMAND} -E copy ${CPM_PACKAGE_LOCK_FILE} + ${CPM_ABSOLUTE_PACKAGE_LOCK_PATH} + ) + endif() + set(CPM_PACKAGE_LOCK_ENABLED true) + endif() +endmacro() + +# registers a package that has been added to CPM +function(CPMRegisterPackage PACKAGE VERSION) + list(APPEND CPM_PACKAGES ${PACKAGE}) + set(CPM_PACKAGES + ${CPM_PACKAGES} + CACHE INTERNAL "" + ) + set("CPM_PACKAGE_${PACKAGE}_VERSION" + ${VERSION} + CACHE INTERNAL "" + ) +endfunction() + +# retrieve the current version of the package to ${OUTPUT} +function(CPMGetPackageVersion PACKAGE OUTPUT) + set(${OUTPUT} + "${CPM_PACKAGE_${PACKAGE}_VERSION}" + PARENT_SCOPE + ) +endfunction() + +# declares a package in FetchContent_Declare +function(cpm_declare_fetch PACKAGE) + if(${CPM_DRY_RUN}) + cpm_message(STATUS "${CPM_INDENT} Package not declared (dry run)") + return() + endif() + + FetchContent_Declare(${PACKAGE} ${ARGN}) +endfunction() + +# returns properties for a package previously defined by cpm_declare_fetch +function(cpm_get_fetch_properties PACKAGE) + if(${CPM_DRY_RUN}) + return() + endif() + + set(${PACKAGE}_SOURCE_DIR + "${CPM_PACKAGE_${PACKAGE}_SOURCE_DIR}" + PARENT_SCOPE + ) + set(${PACKAGE}_BINARY_DIR + "${CPM_PACKAGE_${PACKAGE}_BINARY_DIR}" + PARENT_SCOPE + ) +endfunction() + +function(cpm_store_fetch_properties PACKAGE source_dir binary_dir) + if(${CPM_DRY_RUN}) + return() + endif() + + set(CPM_PACKAGE_${PACKAGE}_SOURCE_DIR + "${source_dir}" + CACHE INTERNAL "" + ) + set(CPM_PACKAGE_${PACKAGE}_BINARY_DIR + "${binary_dir}" + CACHE INTERNAL "" + ) +endfunction() + +# adds a package as a subdirectory if viable, according to provided options +function( + cpm_add_subdirectory + PACKAGE + DOWNLOAD_ONLY + SOURCE_DIR + BINARY_DIR + EXCLUDE + SYSTEM + OPTIONS +) + + if(NOT DOWNLOAD_ONLY AND EXISTS ${SOURCE_DIR}/CMakeLists.txt) + set(addSubdirectoryExtraArgs "") + if(EXCLUDE) + list(APPEND addSubdirectoryExtraArgs EXCLUDE_FROM_ALL) + endif() + if("${SYSTEM}" AND "${CMAKE_VERSION}" VERSION_GREATER_EQUAL "3.25") + # https://cmake.org/cmake/help/latest/prop_dir/SYSTEM.html#prop_dir:SYSTEM + list(APPEND addSubdirectoryExtraArgs SYSTEM) + endif() + if(OPTIONS) + foreach(OPTION ${OPTIONS}) + cpm_parse_option("${OPTION}") + set(${OPTION_KEY} "${OPTION_VALUE}") + endforeach() + endif() + set(CPM_OLD_INDENT "${CPM_INDENT}") + set(CPM_INDENT "${CPM_INDENT} ${PACKAGE}:") + add_subdirectory(${SOURCE_DIR} ${BINARY_DIR} ${addSubdirectoryExtraArgs}) + set(CPM_INDENT "${CPM_OLD_INDENT}") + endif() +endfunction() + +# downloads a previously declared package via FetchContent and exports the variables +# `${PACKAGE}_SOURCE_DIR` and `${PACKAGE}_BINARY_DIR` to the parent scope +function(cpm_fetch_package PACKAGE DOWNLOAD_ONLY populated) + set(${populated} + FALSE + PARENT_SCOPE + ) + if(${CPM_DRY_RUN}) + cpm_message(STATUS "${CPM_INDENT} Package ${PACKAGE} not fetched (dry run)") + return() + endif() + + FetchContent_GetProperties(${PACKAGE}) + + string(TOLOWER "${PACKAGE}" lower_case_name) + + if(NOT ${lower_case_name}_POPULATED) + if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.30.3") + if(DOWNLOAD_ONLY) + # MakeAvailable will call add_subdirectory internally which is not what we want when + # DOWNLOAD_ONLY is set. Populate will only download the dependency without adding it to the + # build + FetchContent_Populate( + ${PACKAGE} + SOURCE_DIR "${CPM_FETCHCONTENT_BASE_DIR}/${lower_case_name}-src" + BINARY_DIR "${CPM_FETCHCONTENT_BASE_DIR}/${lower_case_name}-build" + SUBBUILD_DIR "${CPM_FETCHCONTENT_BASE_DIR}/${lower_case_name}-subbuild" + ${ARGN} + ) + else() + FetchContent_MakeAvailable(${PACKAGE}) + endif() + else() + FetchContent_Populate(${PACKAGE}) + endif() + set(${populated} + TRUE + PARENT_SCOPE + ) + endif() + + cpm_store_fetch_properties( + ${CPM_ARGS_NAME} ${${lower_case_name}_SOURCE_DIR} ${${lower_case_name}_BINARY_DIR} + ) + + set(${PACKAGE}_SOURCE_DIR + ${${lower_case_name}_SOURCE_DIR} + PARENT_SCOPE + ) + set(${PACKAGE}_BINARY_DIR + ${${lower_case_name}_BINARY_DIR} + PARENT_SCOPE + ) +endfunction() + +# splits a package option +function(cpm_parse_option OPTION) + string(REGEX MATCH "^[^ ]+" OPTION_KEY "${OPTION}") + string(LENGTH "${OPTION}" OPTION_LENGTH) + string(LENGTH "${OPTION_KEY}" OPTION_KEY_LENGTH) + if(OPTION_KEY_LENGTH STREQUAL OPTION_LENGTH) + # no value for key provided, assume user wants to set option to "ON" + set(OPTION_VALUE "ON") + else() + math(EXPR OPTION_KEY_LENGTH "${OPTION_KEY_LENGTH}+1") + string(SUBSTRING "${OPTION}" "${OPTION_KEY_LENGTH}" "-1" OPTION_VALUE) + endif() + set(OPTION_KEY + "${OPTION_KEY}" + PARENT_SCOPE + ) + set(OPTION_VALUE + "${OPTION_VALUE}" + PARENT_SCOPE + ) +endfunction() + +# guesses the package version from a git tag +function(cpm_get_version_from_git_tag GIT_TAG RESULT) + string(LENGTH ${GIT_TAG} length) + if(length EQUAL 40) + # GIT_TAG is probably a git hash + set(${RESULT} + 0 + PARENT_SCOPE + ) + else() + string(REGEX MATCH "v?([0123456789.]*).*" _ ${GIT_TAG}) + set(${RESULT} + ${CMAKE_MATCH_1} + PARENT_SCOPE + ) + endif() +endfunction() + +# guesses if the git tag is a commit hash or an actual tag or a branch name. +function(cpm_is_git_tag_commit_hash GIT_TAG RESULT) + string(LENGTH "${GIT_TAG}" length) + # full hash has 40 characters, and short hash has at least 7 characters. + if(length LESS 7 OR length GREATER 40) + set(${RESULT} + 0 + PARENT_SCOPE + ) + else() + if(${GIT_TAG} MATCHES "^[a-fA-F0-9]+$") + set(${RESULT} + 1 + PARENT_SCOPE + ) + else() + set(${RESULT} + 0 + PARENT_SCOPE + ) + endif() + endif() +endfunction() + +function(cpm_prettify_package_arguments OUT_VAR IS_IN_COMMENT) + set(oneValueArgs + NAME + FORCE + VERSION + GIT_TAG + DOWNLOAD_ONLY + GITHUB_REPOSITORY + GITLAB_REPOSITORY + BITBUCKET_REPOSITORY + GIT_REPOSITORY + SOURCE_DIR + FIND_PACKAGE_ARGUMENTS + NO_CACHE + SYSTEM + GIT_SHALLOW + EXCLUDE_FROM_ALL + SOURCE_SUBDIR + ) + set(multiValueArgs URL OPTIONS DOWNLOAD_COMMAND) + cmake_parse_arguments(CPM_ARGS "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + foreach(oneArgName ${oneValueArgs}) + if(DEFINED CPM_ARGS_${oneArgName}) + if(${IS_IN_COMMENT}) + string(APPEND PRETTY_OUT_VAR "#") + endif() + if(${oneArgName} STREQUAL "SOURCE_DIR") + string(REPLACE ${CMAKE_SOURCE_DIR} "\${CMAKE_SOURCE_DIR}" CPM_ARGS_${oneArgName} + ${CPM_ARGS_${oneArgName}} + ) + endif() + string(APPEND PRETTY_OUT_VAR " ${oneArgName} ${CPM_ARGS_${oneArgName}}\n") + endif() + endforeach() + foreach(multiArgName ${multiValueArgs}) + if(DEFINED CPM_ARGS_${multiArgName}) + if(${IS_IN_COMMENT}) + string(APPEND PRETTY_OUT_VAR "#") + endif() + string(APPEND PRETTY_OUT_VAR " ${multiArgName}\n") + foreach(singleOption ${CPM_ARGS_${multiArgName}}) + if(${IS_IN_COMMENT}) + string(APPEND PRETTY_OUT_VAR "#") + endif() + string(APPEND PRETTY_OUT_VAR " \"${singleOption}\"\n") + endforeach() + endif() + endforeach() + + if(NOT "${CPM_ARGS_UNPARSED_ARGUMENTS}" STREQUAL "") + if(${IS_IN_COMMENT}) + string(APPEND PRETTY_OUT_VAR "#") + endif() + string(APPEND PRETTY_OUT_VAR " ") + foreach(CPM_ARGS_UNPARSED_ARGUMENT ${CPM_ARGS_UNPARSED_ARGUMENTS}) + string(APPEND PRETTY_OUT_VAR " ${CPM_ARGS_UNPARSED_ARGUMENT}") + endforeach() + string(APPEND PRETTY_OUT_VAR "\n") + endif() + + set(${OUT_VAR} + ${PRETTY_OUT_VAR} + PARENT_SCOPE + ) + +endfunction() diff --git a/thirdparty/gsl-lite/example/with-CPM/main.cpp b/thirdparty/gsl-lite/example/with-CPM/main.cpp new file mode 100644 index 000000000..acf830a96 --- /dev/null +++ b/thirdparty/gsl-lite/example/with-CPM/main.cpp @@ -0,0 +1,22 @@ + +#include <iostream> + +#include <gsl-lite/gsl-lite.hpp> + +void printCmdArgs( gsl_lite::span<gsl_lite::zstring const> cmdArgs ) +{ + gsl_Expects( !cmdArgs.empty() ); + + auto argsWithoutExeName = cmdArgs.subspan( 1 ); + for ( auto arg : argsWithoutExeName ) + { + std::cout << arg << "\n"; + } +} + +int main( int argc, char* argv[] ) +{ + auto numArgs = gsl_lite::narrow_failfast<std::size_t>( argc ); + auto cmdArgs = gsl_lite::span( argv, numArgs ); + printCmdArgs( cmdArgs ); +} diff --git a/thirdparty/gsl-lite/example/with-Vcpkg/README.md b/thirdparty/gsl-lite/example/with-Vcpkg/README.md new file mode 100644 index 000000000..19087b1dd --- /dev/null +++ b/thirdparty/gsl-lite/example/with-Vcpkg/README.md @@ -0,0 +1,31 @@ +# gsl-lite example project (Vcpkg) + + +This is a simple CMake project that demonstrates how to use *gsl-lite* with the [Vcpkg](https://vcpkg.io/en/package/gsl-lite) package manager. + +Requirements: + +- [CMake](https://cmake.org/) 3.20 or newer must be in the path. +- A C++ compiler must be installed and available in the path. +- Vcpkg must be installed, and the `VCPKG_ROOT` environment variable must refer to the Vcpkg root directory. +- An internet connection must be available to allow Vcpkg to retrieve the *gsl-lite* dependency from GitHub. + +To set up the project, open a command-line window, navigate to the directory containing this readme, and execute the following commands: + + +## Configure +``` +cmake --preset default +``` + + +## Build +``` +cmake --build build/default --config Debug +``` + +## Run + +| Windows | Linux, MacOS | +|----------------------------------|------------------------------------| +| `build\default\Debug\my-program` | `./build/default/Debug/my-program` | diff --git a/thirdparty/gsl-lite/example/with-Vcpkg/main.cpp b/thirdparty/gsl-lite/example/with-Vcpkg/main.cpp new file mode 100644 index 000000000..acf830a96 --- /dev/null +++ b/thirdparty/gsl-lite/example/with-Vcpkg/main.cpp @@ -0,0 +1,22 @@ + +#include <iostream> + +#include <gsl-lite/gsl-lite.hpp> + +void printCmdArgs( gsl_lite::span<gsl_lite::zstring const> cmdArgs ) +{ + gsl_Expects( !cmdArgs.empty() ); + + auto argsWithoutExeName = cmdArgs.subspan( 1 ); + for ( auto arg : argsWithoutExeName ) + { + std::cout << arg << "\n"; + } +} + +int main( int argc, char* argv[] ) +{ + auto numArgs = gsl_lite::narrow_failfast<std::size_t>( argc ); + auto cmdArgs = gsl_lite::span( argv, numArgs ); + printCmdArgs( cmdArgs ); +} diff --git a/thirdparty/gsl-lite/example/with-Vcpkg/vcpkg.json b/thirdparty/gsl-lite/example/with-Vcpkg/vcpkg.json new file mode 100644 index 000000000..5f046228d --- /dev/null +++ b/thirdparty/gsl-lite/example/with-Vcpkg/vcpkg.json @@ -0,0 +1,6 @@ +{ + "name": "my-program", + "dependencies": [ + "gsl-lite" + ] +} diff --git a/thirdparty/gsl-lite/include/gsl-lite/gsl-lite.hpp b/thirdparty/gsl-lite/include/gsl-lite/gsl-lite.hpp new file mode 100644 index 000000000..aa286f2d2 --- /dev/null +++ b/thirdparty/gsl-lite/include/gsl-lite/gsl-lite.hpp @@ -0,0 +1,6014 @@ +// +// For more information see https://github.com/gsl-lite/gsl-lite +// +// gsl-lite is originally based on Microsoft GSL, which is an implementation of the C++ Core Guidelines Support Library: +// https://github.com/microsoft/GSL +// +// Copyright (c) 2015-2019 Martin Moene +// Copyright (c) 2019-2025 Moritz Beutel +// Copyright (c) 2015-2025 Microsoft Corporation. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef GSL_LITE_GSL_LITE_HPP_INCLUDED +#define GSL_LITE_GSL_LITE_HPP_INCLUDED + +#include <exception> // for exception, terminate(), uncaught_exceptions() +#include <limits> +#include <memory> // for addressof(), unique_ptr<>, shared_ptr<> +#include <iosfwd> // for basic_ostream<> +#include <stdexcept> // for logic_error +#include <utility> // for move(), forward<>(), swap() +#include <cstddef> // for size_t, ptrdiff_t, nullptr_t +#include <cstdlib> // for abort() + +#if defined( __has_include ) +# if __has_include( <version> ) +# include <version> +# endif +#endif + +#define gsl_lite_MAJOR 1 +#define gsl_lite_MINOR 0 +#define gsl_lite_PATCH 1 + +#define gsl_lite_VERSION gsl_STRINGIFY(gsl_lite_MAJOR) "." gsl_STRINGIFY(gsl_lite_MINOR) "." gsl_STRINGIFY(gsl_lite_PATCH) + +#define gsl_STRINGIFY( x ) gsl_STRINGIFY_( x ) +#define gsl_STRINGIFY_( x ) #x +#define gsl_CONCAT_( a, b ) gsl_CONCAT2_( a, b ) +#define gsl_CONCAT2_( a, b ) a##b +#define gsl_EVALF_( f ) f() + +// Configuration argument checking: + +#define gsl_DETAIL_CFG_TOGGLE_VALUE_1 1 +#define gsl_DETAIL_CFG_TOGGLE_VALUE_0 1 +#define gsl_DETAIL_CFG_DEFAULTS_VERSION_VALUE_1 1 +#define gsl_DETAIL_CFG_DEFAULTS_VERSION_VALUE_0 1 +#define gsl_DETAIL_CFG_STD_VALUE_98 1 +#define gsl_DETAIL_CFG_STD_VALUE_0 1 +#define gsl_DETAIL_CFG_STD_VALUE_3 1 +#define gsl_DETAIL_CFG_STD_VALUE_03 1 +#define gsl_DETAIL_CFG_STD_VALUE_11 1 +#define gsl_DETAIL_CFG_STD_VALUE_14 1 +#define gsl_DETAIL_CFG_STD_VALUE_17 1 +#define gsl_DETAIL_CFG_STD_VALUE_20 1 +#define gsl_DETAIL_CFG_STD_VALUE_23 1 +#define gsl_DETAIL_CFG_STD_VALUE_26 1 +#define gsl_DETAIL_CFG_NO_VALUE_ 1 +#define gsl_DETAIL_CFG_NO_VALUE_1 1 // many compilers treat the command-line parameter "-Dfoo" as equivalent to "-Dfoo=1", so we tolerate that +#define gsl_CHECK_CFG_TOGGLE_VALUE_( x ) gsl_CONCAT_( gsl_DETAIL_CFG_TOGGLE_VALUE_, x ) +#define gsl_CHECK_CFG_DEFAULTS_VERSION_VALUE_( x ) gsl_CONCAT_( gsl_DETAIL_CFG_DEFAULTS_VERSION_VALUE_, x ) +#define gsl_CHECK_CFG_STD_VALUE_( x ) gsl_CONCAT_( gsl_DETAIL_CFG_STD_VALUE_, x ) +#define gsl_CHECK_CFG_NO_VALUE_( x ) gsl_CONCAT_( gsl_DETAIL_CFG_NO_VALUE, gsl_CONCAT_( _, x ) ) + +// gsl-lite backward compatibility: + +#if defined( gsl_CONFIG_ACKNOWLEDGE_NONSTANDARD_ABI ) +# if ! gsl_CHECK_CFG_NO_VALUE_( gsl_CONFIG_ACKNOWLEDGE_NONSTANDARD_ABI ) +# pragma message (__FILE__ "(" gsl_STRINGIFY( __LINE__ ) "): warning: invalid configuration value gsl_CONFIG_ACKNOWLEDGE_NONSTANDARD_ABI=" gsl_STRINGIFY(gsl_CONFIG_ACKNOWLEDGE_NONSTANDARD_ABI) "; macro must be defined without value") +# endif +#endif + +#if defined( gsl_CONFIG_DEFAULTS_VERSION ) +# if ! gsl_CHECK_CFG_DEFAULTS_VERSION_VALUE_( gsl_CONFIG_DEFAULTS_VERSION ) +# pragma message (__FILE__ "(" gsl_STRINGIFY( __LINE__ ) "): warning: invalid configuration value gsl_CONFIG_DEFAULTS_VERSION=" gsl_STRINGIFY(gsl_CONFIG_DEFAULTS_VERSION) ", must be 0 or 1") +# endif +#else +# define gsl_CONFIG_DEFAULTS_VERSION gsl_lite_MAJOR // default +#endif +#define gsl_CONFIG_DEFAULTS_VERSION_() gsl_CONFIG_DEFAULTS_VERSION + +#if defined( gsl_CONFIG_ALLOWS_SPAN_CONTAINER_CTOR ) +# if ! gsl_CHECK_CFG_TOGGLE_VALUE_( gsl_CONFIG_ALLOWS_SPAN_CONTAINER_CTOR ) +# pragma message (__FILE__ "(" gsl_STRINGIFY( __LINE__ ) "): warning: invalid configuration value gsl_CONFIG_ALLOWS_SPAN_CONTAINER_CTOR=" gsl_STRINGIFY(gsl_CONFIG_ALLOWS_SPAN_CONTAINER_CTOR) ", must be 0 or 1") +# endif +# define gsl_CONFIG_ALLOWS_UNCONSTRAINED_SPAN_CONTAINER_CTOR gsl_CONFIG_ALLOWS_SPAN_CONTAINER_CTOR +# pragma message (__FILE__ "(" gsl_STRINGIFY( __LINE__ ) "): warning: configuration macro gsl_CONFIG_ALLOWS_SPAN_CONTAINER_CTOR is deprecated since gsl-lite 0.7; if the constrained container constructor is not usable, define gsl_CONFIG_ALLOWS_UNCONSTRAINED_SPAN_CONTAINER_CTOR instead") +#endif + +#if defined( gsl_CONFIG_CONTRACT_LEVEL_ON ) +# if ! gsl_CHECK_CFG_NO_VALUE_( gsl_CONFIG_CONTRACT_LEVEL_ON ) +# pragma message (__FILE__ "(" gsl_STRINGIFY( __LINE__ ) "): warning: invalid configuration value gsl_CONFIG_CONTRACT_LEVEL_ON=" gsl_STRINGIFY(gsl_CONFIG_CONTRACT_LEVEL_ON) "; macro must be defined without value") +# endif +# pragma message (__FILE__ "(" gsl_STRINGIFY( __LINE__ ) "): warning: configuration macro gsl_CONFIG_CONTRACT_LEVEL_ON is deprecated since gsl-lite v0.36; define gsl_CONFIG_CONTRACT_CHECKING_ON instead") +# define gsl_CONFIG_CONTRACT_CHECKING_ON +#endif +#if defined( gsl_CONFIG_CONTRACT_LEVEL_OFF ) +# if ! gsl_CHECK_CFG_NO_VALUE_( gsl_CONFIG_CONTRACT_LEVEL_OFF ) +# pragma message (__FILE__ "(" gsl_STRINGIFY( __LINE__ ) "): warning: invalid configuration value gsl_CONFIG_CONTRACT_LEVEL_OFF=" gsl_STRINGIFY(gsl_CONFIG_CONTRACT_LEVEL_OFF) "; macro must be defined without value") +# endif +# pragma message (__FILE__ "(" gsl_STRINGIFY( __LINE__ ) "): warning: configuration macro gsl_CONFIG_CONTRACT_LEVEL_OFF is deprecated since gsl-lite v0.36; define gsl_CONFIG_CONTRACT_CHECKING_OFF instead") +# define gsl_CONFIG_CONTRACT_CHECKING_OFF +#endif +#if defined( gsl_CONFIG_CONTRACT_LEVEL_EXPECTS_ONLY ) +# if ! gsl_CHECK_CFG_NO_VALUE_( gsl_CONFIG_CONTRACT_LEVEL_EXPECTS_ONLY ) +# pragma message (__FILE__ "(" gsl_STRINGIFY( __LINE__ ) "): warning: invalid configuration value gsl_CONFIG_CONTRACT_LEVEL_EXPECTS_ONLY=" gsl_STRINGIFY(gsl_CONFIG_CONTRACT_LEVEL_EXPECTS_ONLY) "; macro must be defined without value") +# endif +# pragma message (__FILE__ "(" gsl_STRINGIFY( __LINE__ ) "): warning: configuration macro gsl_CONFIG_CONTRACT_LEVEL_EXPECTS_ONLY is deprecated since gsl-lite v0.36; define gsl_CONFIG_CONTRACT_CHECKING_ENSURES_OFF and gsl_CONFIG_CONTRACT_CHECKING_ASSERT_OFF instead") +# define gsl_CONFIG_CONTRACT_CHECKING_ON +# define gsl_CONFIG_CONTRACT_CHECKING_ENSURES_OFF +# define gsl_CONFIG_CONTRACT_CHECKING_ASSERT_OFF +#elif defined( gsl_CONFIG_CONTRACT_LEVEL_ENSURES_ONLY ) +# if ! gsl_CHECK_CFG_NO_VALUE_( gsl_CONFIG_CONTRACT_LEVEL_ENSURES_ONLY ) +# pragma message (__FILE__ "(" gsl_STRINGIFY( __LINE__ ) "): warning: invalid configuration value gsl_CONFIG_CONTRACT_LEVEL_ENSURES_ONLY=" gsl_STRINGIFY(gsl_CONFIG_CONTRACT_LEVEL_ENSURES_ONLY) "; macro must be defined without value") +# endif +# pragma message (__FILE__ "(" gsl_STRINGIFY( __LINE__ ) "): warning: configuration macro gsl_CONFIG_CONTRACT_LEVEL_ENSURES_ONLY is deprecated since gsl-lite v0.36; define gsl_CONFIG_CONTRACT_CHECKING_EXPECTS_OFF and gsl_CONFIG_CONTRACT_CHECKING_ASSERT_OFF instead") +# define gsl_CONFIG_CONTRACT_CHECKING_ON +# define gsl_CONFIG_CONTRACT_CHECKING_EXPECTS_OFF +# define gsl_CONFIG_CONTRACT_CHECKING_ASSERT_OFF +#endif + +// M-GSL compatibility: + +#if defined( GSL_THROW_ON_CONTRACT_VIOLATION ) +# pragma message (__FILE__ "(" gsl_STRINGIFY( __LINE__ ) "): warning: do not use legacy Microsoft GSL configuration macro GSL_THROW_ON_CONTRACT_VIOLATION to configure gsl-lite; define gsl_CONFIG_CONTRACT_VIOLATION_THROWS instead") +# if ! gsl_CHECK_CFG_NO_VALUE_( GSL_THROW_ON_CONTRACT_VIOLATION ) +# pragma message (__FILE__ "(" gsl_STRINGIFY( __LINE__ ) "): warning: invalid configuration value GSL_THROW_ON_CONTRACT_VIOLATION=" gsl_STRINGIFY(GSL_THROW_ON_CONTRACT_VIOLATION) "; macro must be defined without value") +# endif +# define gsl_CONFIG_CONTRACT_VIOLATION_THROWS +#endif + +#if defined( GSL_TERMINATE_ON_CONTRACT_VIOLATION ) +# pragma message (__FILE__ "(" gsl_STRINGIFY( __LINE__ ) "): warning: do not use legacy Microsoft GSL configuration macro GSL_TERMINATE_ON_CONTRACT_VIOLATION to configure gsl-lite; define gsl_CONFIG_CONTRACT_VIOLATION_TERMINATES instead") +# if ! gsl_CHECK_CFG_NO_VALUE_( GSL_TERMINATE_ON_CONTRACT_VIOLATION ) +# pragma message (__FILE__ "(" gsl_STRINGIFY( __LINE__ ) "): warning: invalid configuration value GSL_TERMINATE_ON_CONTRACT_VIOLATION=" gsl_STRINGIFY(GSL_TERMINATE_ON_CONTRACT_VIOLATION) "; macro must be defined without value") +# endif +# define gsl_CONFIG_CONTRACT_VIOLATION_TERMINATES +#endif + +#if defined( GSL_UNENFORCED_ON_CONTRACT_VIOLATION ) +# pragma message (__FILE__ "(" gsl_STRINGIFY( __LINE__ ) "): warning: do not use legacy Microsoft GSL configuration macro GSL_UNENFORCED_ON_CONTRACT_VIOLATION to configure gsl-lite; define gsl_CONFIG_CONTRACT_CHECKING_OFF instead") +# if ! gsl_CHECK_CFG_NO_VALUE_( GSL_UNENFORCED_ON_CONTRACT_VIOLATION ) +# pragma message (__FILE__ "(" gsl_STRINGIFY( __LINE__ ) "): warning: invalid configuration value GSL_UNENFORCED_ON_CONTRACT_VIOLATION=" gsl_STRINGIFY(GSL_UNENFORCED_ON_CONTRACT_VIOLATION) "; macro must be defined without value") +# endif +# define gsl_CONFIG_CONTRACT_CHECKING_OFF +#endif + +// Configuration: Features + +#if defined( gsl_FEATURE_GSL_COMPATIBILITY_MODE ) +# if ! gsl_CHECK_CFG_TOGGLE_VALUE_( gsl_FEATURE_GSL_COMPATIBILITY_MODE ) +# pragma message (__FILE__ "(" gsl_STRINGIFY( __LINE__ ) "): warning: invalid configuration value gsl_FEATURE_GSL_COMPATIBILITY_MODE=" gsl_STRINGIFY(gsl_FEATURE_OWNER_MACRO) ", must be 0 or 1") +# endif +#else +# define gsl_FEATURE_GSL_COMPATIBILITY_MODE (gsl_CONFIG_DEFAULTS_VERSION == 0) // default +#endif +#define gsl_FEATURE_GSL_COMPATIBILITY_MODE_() gsl_FEATURE_GSL_COMPATIBILITY_MODE + +#if defined( gsl_FEATURE_WITH_CONTAINER_TO_STD ) +# if ! gsl_CHECK_CFG_STD_VALUE_( gsl_FEATURE_WITH_CONTAINER_TO_STD ) +# pragma message (__FILE__ "(" gsl_STRINGIFY( __LINE__ ) "): warning: invalid configuration value gsl_FEATURE_WITH_CONTAINER_TO_STD=" gsl_STRINGIFY(gsl_FEATURE_WITH_CONTAINER_TO_STD) ", must be 98, 3, 11, 14, 17, or 20") +# endif +#else +# if gsl_CONFIG_DEFAULTS_VERSION >= 1 +# define gsl_FEATURE_WITH_CONTAINER_TO_STD 0 // version-1 default +# else // gsl_CONFIG_DEFAULTS_VERSION == 0 +# define gsl_FEATURE_WITH_CONTAINER_TO_STD 99 // version-0 default +# endif // gsl_CONFIG_DEFAULTS_VERSION >= 1 +#endif +#define gsl_FEATURE_WITH_CONTAINER_TO_STD_() gsl_FEATURE_WITH_CONTAINER_TO_STD + +#if defined( gsl_FEATURE_MAKE_SPAN_TO_STD ) +# if ! gsl_CHECK_CFG_STD_VALUE_( gsl_FEATURE_MAKE_SPAN_TO_STD ) +# pragma message (__FILE__ "(" gsl_STRINGIFY( __LINE__ ) "): warning: invalid configuration value gsl_FEATURE_MAKE_SPAN_TO_STD=" gsl_STRINGIFY(gsl_FEATURE_MAKE_SPAN_TO_STD) ", must be 98, 3, 11, 14, 17, or 20") +# endif +#else +# define gsl_FEATURE_MAKE_SPAN_TO_STD 99 // default +#endif +#define gsl_FEATURE_MAKE_SPAN_TO_STD_() gsl_FEATURE_MAKE_SPAN_TO_STD + +#if defined( gsl_FEATURE_BYTE_SPAN_TO_STD ) +# if ! gsl_CHECK_CFG_STD_VALUE_( gsl_FEATURE_BYTE_SPAN_TO_STD ) +# pragma message (__FILE__ "(" gsl_STRINGIFY( __LINE__ ) "): warning: invalid configuration value gsl_FEATURE_BYTE_SPAN_TO_STD=" gsl_STRINGIFY(gsl_FEATURE_BYTE_SPAN_TO_STD) ", must be 98, 3, 11, 14, 17, or 20") +# endif +#else +# define gsl_FEATURE_BYTE_SPAN_TO_STD 99 // default +#endif +#define gsl_FEATURE_BYTE_SPAN_TO_STD_() gsl_FEATURE_BYTE_SPAN_TO_STD + +#if defined( gsl_FEATURE_IMPLICIT_MACRO ) +# if ! gsl_CHECK_CFG_TOGGLE_VALUE_( gsl_FEATURE_IMPLICIT_MACRO ) +# pragma message (__FILE__ "(" gsl_STRINGIFY( __LINE__ ) "): warning: invalid configuration value gsl_FEATURE_IMPLICIT_MACRO=" gsl_STRINGIFY(gsl_FEATURE_IMPLICIT_MACRO) ", must be 0 or 1") +# endif +# if gsl_FEATURE_IMPLICIT_MACRO +# error configuration value gsl_FEATURE_IMPLICIT_MACRO=1 is no longer supported since gsl-lite v1.0 +# endif // gsl_FEATURE_IMPLICIT_MACRO +#else +# define gsl_FEATURE_IMPLICIT_MACRO 0 +#endif +#define gsl_FEATURE_IMPLICIT_MACRO_() gsl_FEATURE_IMPLICIT_MACRO + +#if defined( gsl_FEATURE_OWNER_MACRO ) +# if ! gsl_CHECK_CFG_TOGGLE_VALUE_( gsl_FEATURE_OWNER_MACRO ) +# pragma message (__FILE__ "(" gsl_STRINGIFY( __LINE__ ) "): warning: invalid configuration value gsl_FEATURE_OWNER_MACRO=" gsl_STRINGIFY(gsl_FEATURE_OWNER_MACRO) ", must be 0 or 1") +# endif +# if gsl_FEATURE_OWNER_MACRO +# error configuration value gsl_FEATURE_OWNER_MACRO=1 is no longer supported since gsl-lite v1.0 +# endif // gsl_FEATURE_OWNER_MACRO +#else +# define gsl_FEATURE_OWNER_MACRO 0 +#endif +#define gsl_FEATURE_OWNER_MACRO_() gsl_FEATURE_OWNER_MACRO + +#if defined( gsl_FEATURE_STRING_SPAN ) +# if ! gsl_CHECK_CFG_TOGGLE_VALUE_( gsl_FEATURE_STRING_SPAN ) +# pragma message (__FILE__ "(" gsl_STRINGIFY( __LINE__ ) "): warning: invalid configuration value gsl_FEATURE_STRING_SPAN=" gsl_STRINGIFY(gsl_FEATURE_STRING_SPAN) ", must be 0 or 1") +# endif +#else +# define gsl_FEATURE_STRING_SPAN (gsl_CONFIG_DEFAULTS_VERSION == 0) // default +#endif +#define gsl_FEATURE_STRING_SPAN_() gsl_FEATURE_STRING_SPAN + +#if defined( gsl_FEATURE_BYTE ) +# if ! gsl_CHECK_CFG_TOGGLE_VALUE_( gsl_FEATURE_BYTE ) +# pragma message (__FILE__ "(" gsl_STRINGIFY( __LINE__ ) "): warning: invalid configuration value gsl_FEATURE_BYTE=" gsl_STRINGIFY(gsl_FEATURE_BYTE) ", must be 0 or 1") +# endif +#else +# define gsl_FEATURE_BYTE (gsl_CONFIG_DEFAULTS_VERSION == 0) // default +#endif +#define gsl_FEATURE_BYTE_() gsl_FEATURE_BYTE + +#if defined( gsl_FEATURE_EXPERIMENTAL_RETURN_GUARD ) +# if ! gsl_CHECK_CFG_TOGGLE_VALUE_( gsl_FEATURE_EXPERIMENTAL_RETURN_GUARD ) +# pragma message (__FILE__ "(" gsl_STRINGIFY( __LINE__ ) "): warning: invalid configuration value gsl_FEATURE_EXPERIMENTAL_RETURN_GUARD=" gsl_STRINGIFY(gsl_FEATURE_EXPERIMENTAL_RETURN_GUARD) ", must be 0 or 1") +# endif +#else +# define gsl_FEATURE_EXPERIMENTAL_RETURN_GUARD 0 // default +#endif +#define gsl_FEATURE_EXPERIMENTAL_RETURN_GUARD_() gsl_FEATURE_EXPERIMENTAL_RETURN_GUARD + +#if defined( gsl_FEATURE_GSL_LITE_NAMESPACE ) +# if ! gsl_CHECK_CFG_TOGGLE_VALUE_( gsl_FEATURE_GSL_LITE_NAMESPACE ) +# pragma message (__FILE__ "(" gsl_STRINGIFY( __LINE__ ) "): warning: invalid configuration value gsl_FEATURE_GSL_LITE_NAMESPACE=" gsl_STRINGIFY(gsl_FEATURE_GSL_LITE_NAMESPACE) ", must be 0 or 1") +# endif +# if ! gsl_FEATURE_GSL_LITE_NAMESPACE +# error gsl_FEATURE_GSL_LITE_NAMESPACE is a required feature since gsl-lite v1.0 and cannot be switched off +# endif +#else +# define gsl_FEATURE_GSL_LITE_NAMESPACE 1 +#endif +#define gsl_FEATURE_GSL_LITE_NAMESPACE_() gsl_FEATURE_GSL_LITE_NAMESPACE + +// Configuration: Other + +#if defined( gsl_CONFIG_TRANSPARENT_NOT_NULL ) +# if ! gsl_CHECK_CFG_TOGGLE_VALUE_( gsl_CONFIG_TRANSPARENT_NOT_NULL ) +# pragma message (__FILE__ "(" gsl_STRINGIFY( __LINE__ ) "): warning: invalid configuration value gsl_CONFIG_TRANSPARENT_NOT_NULL=" gsl_STRINGIFY(gsl_CONFIG_TRANSPARENT_NOT_NULL) ", must be 0 or 1") +# endif +# if gsl_CONFIG_TRANSPARENT_NOT_NULL && defined( gsl_CONFIG_NOT_NULL_GET_BY_CONST_REF ) +# error configuration option gsl_CONFIG_NOT_NULL_GET_BY_CONST_REF is meaningless if gsl_CONFIG_TRANSPARENT_NOT_NULL=1 +# endif +#else +# define gsl_CONFIG_TRANSPARENT_NOT_NULL (gsl_CONFIG_DEFAULTS_VERSION >= 1) // default +#endif +#define gsl_CONFIG_TRANSPARENT_NOT_NULL_() gsl_CONFIG_TRANSPARENT_NOT_NULL + +#if ! defined( gsl_CONFIG_DEPRECATE_TO_LEVEL ) +# if gsl_CONFIG_DEFAULTS_VERSION >= 1 +# define gsl_CONFIG_DEPRECATE_TO_LEVEL 9 +# else +# define gsl_CONFIG_DEPRECATE_TO_LEVEL 0 +# endif +#endif + +#if defined( gsl_CONFIG_SPAN_INDEX_TYPE ) +# if ! defined( gsl_CONFIG_ACKNOWLEDGE_NONSTANDARD_ABI ) +# pragma message (__FILE__ "(" gsl_STRINGIFY( __LINE__ ) "): warning: defining a custom gsl_CONFIG_SPAN_INDEX_TYPE changes the ABI of gsl-lite, which may lead to ODR violations and undefined behavior; define the macro gsl_CONFIG_ACKNOWLEDGE_NONSTANDARD_ABI to explicitly acknowledge that you are using gsl-lite with a non-standard ABI and that you control the build flags of all components linked into your target") +# endif +#else // ! defined( gsl_CONFIG_SPAN_INDEX_TYPE ) +# define gsl_CONFIG_SPAN_INDEX_TYPE std::size_t +#endif +#define gsl_CONFIG_SPAN_INDEX_TYPE_() gsl_CONFIG_SPAN_INDEX_TYPE + +#if defined( gsl_CONFIG_INDEX_TYPE ) +# if ! defined( gsl_CONFIG_ACKNOWLEDGE_NONSTANDARD_ABI ) +# pragma message (__FILE__ "(" gsl_STRINGIFY( __LINE__ ) "): warning: defining a custom gsl_CONFIG_INDEX_TYPE changes the ABI of gsl-lite, which may lead to ODR violations and undefined behavior; define the macro gsl_CONFIG_ACKNOWLEDGE_NONSTANDARD_ABI to explicitly acknowledge that you are using gsl-lite with a non-standard ABI and that you control the build flags of all components linked into your target") +# endif +#else // ! defined( gsl_CONFIG_INDEX_TYPE ) +# if gsl_CONFIG_DEFAULTS_VERSION >= 1 +// p0122r3 uses std::ptrdiff_t +# define gsl_CONFIG_INDEX_TYPE std::ptrdiff_t +# else +# if ! defined( gsl_CONFIG_ACKNOWLEDGE_NONSTANDARD_ABI ) +# pragma message (__FILE__ "(" gsl_STRINGIFY( __LINE__ ) "): warning: with version-0 defaults, gsl_CONFIG_INDEX_TYPE defaults to gsl_CONFIG_SPAN_INDEX_TYPE, which changes the ABI of gsl-lite and may lead to ODR violations and undefined behavior; use version-1 defaults or define the macro gsl_CONFIG_ACKNOWLEDGE_NONSTANDARD_ABI to explicitly acknowledge that you are using gsl-lite with a non-standard ABI and that you control the build flags of all components linked into your target") +# endif +# define gsl_CONFIG_INDEX_TYPE gsl_CONFIG_SPAN_INDEX_TYPE +# endif +#endif +#define gsl_CONFIG_INDEX_TYPE_() gsl_CONFIG_INDEX_TYPE + +#if defined( gsl_CONFIG_NOT_NULL_EXPLICIT_CTOR ) +# if ! gsl_CHECK_CFG_TOGGLE_VALUE_( gsl_CONFIG_NOT_NULL_EXPLICIT_CTOR ) +# pragma message (__FILE__ "(" gsl_STRINGIFY( __LINE__ ) "): warning: invalid configuration value gsl_CONFIG_NOT_NULL_EXPLICIT_CTOR=" gsl_STRINGIFY(gsl_CONFIG_NOT_NULL_EXPLICIT_CTOR) ", must be 0 or 1") +# endif +#else +# define gsl_CONFIG_NOT_NULL_EXPLICIT_CTOR (gsl_CONFIG_DEFAULTS_VERSION >= 1) // default +#endif +#define gsl_CONFIG_NOT_NULL_EXPLICIT_CTOR_() gsl_CONFIG_NOT_NULL_EXPLICIT_CTOR + +#if defined( gsl_CONFIG_NOT_NULL_GET_BY_CONST_REF ) +# if ! gsl_CHECK_CFG_TOGGLE_VALUE_( gsl_CONFIG_NOT_NULL_GET_BY_CONST_REF ) +# pragma message (__FILE__ "(" gsl_STRINGIFY( __LINE__ ) "): warning: invalid configuration value gsl_CONFIG_NOT_NULL_GET_BY_CONST_REF=" gsl_STRINGIFY(gsl_CONFIG_NOT_NULL_GET_BY_CONST_REF) ", must be 0 or 1") +# endif +#else +# define gsl_CONFIG_NOT_NULL_GET_BY_CONST_REF 0 // default +#endif +#define gsl_CONFIG_NOT_NULL_GET_BY_CONST_REF_() gsl_CONFIG_NOT_NULL_GET_BY_CONST_REF + +#if defined( gsl_CONFIG_CONFIRMS_COMPILATION_ERRORS ) +# if ! gsl_CHECK_CFG_TOGGLE_VALUE_( gsl_CONFIG_CONFIRMS_COMPILATION_ERRORS ) +# pragma message (__FILE__ "(" gsl_STRINGIFY( __LINE__ ) "): warning: invalid configuration value gsl_CONFIG_CONFIRMS_COMPILATION_ERRORS=" gsl_STRINGIFY(gsl_CONFIG_CONFIRMS_COMPILATION_ERRORS) ", must be 0 or 1") +# endif +#else +# define gsl_CONFIG_CONFIRMS_COMPILATION_ERRORS 0 // default +#endif +#define gsl_CONFIG_CONFIRMS_COMPILATION_ERRORS_() gsl_CONFIG_CONFIRMS_COMPILATION_ERRORS + +#if defined( gsl_CONFIG_ALLOWS_SPAN_COMPARISON ) +# if ! gsl_CHECK_CFG_TOGGLE_VALUE_( gsl_CONFIG_ALLOWS_SPAN_COMPARISON ) +# pragma message (__FILE__ "(" gsl_STRINGIFY( __LINE__ ) "): warning: invalid configuration value gsl_CONFIG_ALLOWS_SPAN_COMPARISON=" gsl_STRINGIFY(gsl_CONFIG_ALLOWS_SPAN_COMPARISON) ", must be 0 or 1") +# endif +#else +# define gsl_CONFIG_ALLOWS_SPAN_COMPARISON (gsl_CONFIG_DEFAULTS_VERSION == 0) // default +#endif +#define gsl_CONFIG_ALLOWS_SPAN_COMPARISON_() gsl_CONFIG_ALLOWS_SPAN_COMPARISON + +#if defined( gsl_CONFIG_ALLOWS_NONSTRICT_SPAN_COMPARISON ) +# if ! gsl_CHECK_CFG_TOGGLE_VALUE_( gsl_CONFIG_ALLOWS_NONSTRICT_SPAN_COMPARISON ) +# pragma message (__FILE__ "(" gsl_STRINGIFY( __LINE__ ) "): warning: invalid configuration value gsl_CONFIG_ALLOWS_NONSTRICT_SPAN_COMPARISON=" gsl_STRINGIFY(gsl_CONFIG_ALLOWS_NONSTRICT_SPAN_COMPARISON) ", must be 0 or 1") +# endif +#else +# define gsl_CONFIG_ALLOWS_NONSTRICT_SPAN_COMPARISON 1 // default +#endif +#define gsl_CONFIG_ALLOWS_NONSTRICT_SPAN_COMPARISON_() gsl_CONFIG_ALLOWS_NONSTRICT_SPAN_COMPARISON + +#if defined( gsl_CONFIG_ALLOWS_UNCONSTRAINED_SPAN_CONTAINER_CTOR ) +# if ! gsl_CHECK_CFG_TOGGLE_VALUE_( gsl_CONFIG_ALLOWS_UNCONSTRAINED_SPAN_CONTAINER_CTOR ) +# pragma message (__FILE__ "(" gsl_STRINGIFY( __LINE__ ) "): warning: invalid configuration value gsl_CONFIG_ALLOWS_UNCONSTRAINED_SPAN_CONTAINER_CTOR=" gsl_STRINGIFY(gsl_CONFIG_ALLOWS_UNCONSTRAINED_SPAN_CONTAINER_CTOR) ", must be 0 or 1") +# endif +#else +# define gsl_CONFIG_ALLOWS_UNCONSTRAINED_SPAN_CONTAINER_CTOR 0 // default +#endif +#define gsl_CONFIG_ALLOWS_UNCONSTRAINED_SPAN_CONTAINER_CTOR_() gsl_CONFIG_ALLOWS_UNCONSTRAINED_SPAN_CONTAINER_CTOR + +#if defined( gsl_CONFIG_NARROW_THROWS_ON_TRUNCATION ) +# if ! gsl_CHECK_CFG_TOGGLE_VALUE_( gsl_CONFIG_NARROW_THROWS_ON_TRUNCATION ) +# pragma message (__FILE__ "(" gsl_STRINGIFY( __LINE__ ) "): warning: invalid configuration value gsl_CONFIG_NARROW_THROWS_ON_TRUNCATION=" gsl_STRINGIFY(gsl_CONFIG_NARROW_THROWS_ON_TRUNCATION) ", must be 0 or 1") +# endif +# if ! gsl_CONFIG_NARROW_THROWS_ON_TRUNCATION && ! defined( gsl_CONFIG_ACKNOWLEDGE_NONSTANDARD_ABI ) +# pragma message (__FILE__ "(" gsl_STRINGIFY( __LINE__ ) "): warning: the configuration value gsl_CONFIG_NARROW_THROWS_ON_TRUNCATION=0 changes the ABI of gsl-lite, which may lead to ODR violations and undefined behavior; define the macro gsl_CONFIG_ACKNOWLEDGE_NONSTANDARD_ABI to explicitly acknowledge that you are using gsl-lite with a non-standard ABI and that you control the build flags of all components linked into your target") +# endif +#else +# define gsl_CONFIG_NARROW_THROWS_ON_TRUNCATION (gsl_CONFIG_DEFAULTS_VERSION >= 1) // default +# if gsl_CONFIG_DEFAULTS_VERSION < 1 && ! defined( gsl_CONFIG_ACKNOWLEDGE_NONSTANDARD_ABI ) +# pragma message (__FILE__ "(" gsl_STRINGIFY( __LINE__ ) "): warning: with version-0 defaults, gsl_CONFIG_NARROW_THROWS_ON_TRUNCATION defaults to 0, which changes the ABI of gsl-lite and may lead to ODR violations and undefined behavior; use version-1 defaults or define the macro gsl_CONFIG_ACKNOWLEDGE_NONSTANDARD_ABI to explicitly acknowledge that you are using gsl-lite with a non-standard ABI and that you control the build flags of all components linked into your target") +# endif +#endif +#define gsl_CONFIG_NARROW_THROWS_ON_TRUNCATION_() gsl_CONFIG_NARROW_THROWS_ON_TRUNCATION + +#if defined( gsl_CONFIG_VALIDATES_UNENFORCED_CONTRACT_EXPRESSIONS ) +# if ! gsl_CHECK_CFG_TOGGLE_VALUE_( gsl_CONFIG_VALIDATES_UNENFORCED_CONTRACT_EXPRESSIONS ) +# pragma message (__FILE__ "(" gsl_STRINGIFY( __LINE__ ) "): warning: invalid configuration value gsl_CONFIG_VALIDATES_UNENFORCED_CONTRACT_EXPRESSIONS=" gsl_STRINGIFY(gsl_CONFIG_VALIDATES_UNENFORCED_CONTRACT_EXPRESSIONS) ", must be 0 or 1") +# endif +#else +# define gsl_CONFIG_VALIDATES_UNENFORCED_CONTRACT_EXPRESSIONS 1 // default +#endif +#define gsl_CONFIG_VALIDATES_UNENFORCED_CONTRACT_EXPRESSIONS_() gsl_CONFIG_VALIDATES_UNENFORCED_CONTRACT_EXPRESSIONS + +#if defined( gsl_CONFIG_CONTRACT_CHECKING_EXPECTS_OFF ) +# if ! gsl_CHECK_CFG_NO_VALUE_( gsl_CONFIG_CONTRACT_CHECKING_EXPECTS_OFF ) +# pragma message (__FILE__ "(" gsl_STRINGIFY( __LINE__ ) "): warning: invalid configuration value gsl_CONFIG_CONTRACT_CHECKING_EXPECTS_OFF=" gsl_STRINGIFY(gsl_CONFIG_CONTRACT_CHECKING_EXPECTS_OFF) "; macro must be defined without value") +# endif +#endif +#if defined( gsl_CONFIG_CONTRACT_CHECKING_ENSURES_OFF ) +# if ! gsl_CHECK_CFG_NO_VALUE_( gsl_CONFIG_CONTRACT_CHECKING_ENSURES_OFF ) +# pragma message (__FILE__ "(" gsl_STRINGIFY( __LINE__ ) "): warning: invalid configuration value gsl_CONFIG_CONTRACT_CHECKING_ENSURES_OFF=" gsl_STRINGIFY(gsl_CONFIG_CONTRACT_CHECKING_ENSURES_OFF) "; macro must be defined without value") +# endif +#endif +#if defined( gsl_CONFIG_CONTRACT_CHECKING_ASSERT_OFF ) +# if ! gsl_CHECK_CFG_NO_VALUE_( gsl_CONFIG_CONTRACT_CHECKING_ASSERT_OFF ) +# pragma message (__FILE__ "(" gsl_STRINGIFY( __LINE__ ) "): warning: invalid configuration value gsl_CONFIG_CONTRACT_CHECKING_ASSERT_OFF=" gsl_STRINGIFY(gsl_CONFIG_CONTRACT_CHECKING_ASSERT_OFF) "; macro must be defined without value") +# endif +#endif +#if defined( gsl_CONFIG_CONTRACT_CHECKING_AUDIT ) +# if ! gsl_CHECK_CFG_NO_VALUE_( gsl_CONFIG_CONTRACT_CHECKING_AUDIT ) +# pragma message (__FILE__ "(" gsl_STRINGIFY( __LINE__ ) "): warning: invalid configuration value gsl_CONFIG_CONTRACT_CHECKING_AUDIT=" gsl_STRINGIFY(gsl_CONFIG_CONTRACT_CHECKING_AUDIT) "; macro must be defined without value") +# endif +#endif +#if defined( gsl_CONFIG_CONTRACT_CHECKING_ON ) +# if ! gsl_CHECK_CFG_NO_VALUE_( gsl_CONFIG_CONTRACT_CHECKING_ON ) +# pragma message (__FILE__ "(" gsl_STRINGIFY( __LINE__ ) "): warning: invalid configuration value gsl_CONFIG_CONTRACT_CHECKING_ON=" gsl_STRINGIFY(gsl_CONFIG_CONTRACT_CHECKING_ON) "; macro must be defined without value") +# endif +#endif +#if defined( gsl_CONFIG_CONTRACT_CHECKING_OFF ) +# if ! gsl_CHECK_CFG_NO_VALUE_( gsl_CONFIG_CONTRACT_CHECKING_OFF ) +# pragma message (__FILE__ "(" gsl_STRINGIFY( __LINE__ ) "): warning: invalid configuration value gsl_CONFIG_CONTRACT_CHECKING_OFF=" gsl_STRINGIFY(gsl_CONFIG_CONTRACT_CHECKING_OFF) "; macro must be defined without value") +# endif +#endif +#if defined( gsl_CONFIG_DEVICE_CONTRACT_CHECKING_AUDIT ) +# if ! gsl_CHECK_CFG_NO_VALUE_( gsl_CONFIG_DEVICE_CONTRACT_CHECKING_AUDIT ) +# pragma message (__FILE__ "(" gsl_STRINGIFY( __LINE__ ) "): warning: invalid configuration value gsl_CONFIG_DEVICE_CONTRACT_CHECKING_AUDIT=" gsl_STRINGIFY(gsl_CONFIG_DEVICE_CONTRACT_CHECKING_AUDIT) "; macro must be defined without value") +# endif +#endif +#if defined( gsl_CONFIG_DEVICE_CONTRACT_CHECKING_ON ) +# if ! gsl_CHECK_CFG_NO_VALUE_( gsl_CONFIG_DEVICE_CONTRACT_CHECKING_ON ) +# pragma message (__FILE__ "(" gsl_STRINGIFY( __LINE__ ) "): warning: invalid configuration value gsl_CONFIG_DEVICE_CONTRACT_CHECKING_ON=" gsl_STRINGIFY(gsl_CONFIG_DEVICE_CONTRACT_CHECKING_ON) "; macro must be defined without value") +# endif +#endif +#if defined( gsl_CONFIG_DEVICE_CONTRACT_CHECKING_OFF ) +# if ! gsl_CHECK_CFG_NO_VALUE_( gsl_CONFIG_DEVICE_CONTRACT_CHECKING_OFF ) +# pragma message (__FILE__ "(" gsl_STRINGIFY( __LINE__ ) "): warning: invalid configuration value gsl_CONFIG_DEVICE_CONTRACT_CHECKING_OFF=" gsl_STRINGIFY(gsl_CONFIG_DEVICE_CONTRACT_CHECKING_OFF) "; macro must be defined without value") +# endif +#endif +#if defined( gsl_CONFIG_CONTRACT_VIOLATION_THROWS ) +# if ! gsl_CHECK_CFG_NO_VALUE_( gsl_CONFIG_CONTRACT_VIOLATION_THROWS ) +# pragma message (__FILE__ "(" gsl_STRINGIFY( __LINE__ ) "): warning: invalid configuration value gsl_CONFIG_CONTRACT_VIOLATION_THROWS=" gsl_STRINGIFY(gsl_CONFIG_CONTRACT_VIOLATION_THROWS) "; macro must be defined without value") +# endif +#endif +#if defined( gsl_CONFIG_CONTRACT_VIOLATION_TERMINATES ) +# if ! gsl_CHECK_CFG_NO_VALUE_( gsl_CONFIG_CONTRACT_VIOLATION_TERMINATES ) +# pragma message (__FILE__ "(" gsl_STRINGIFY( __LINE__ ) "): warning: invalid configuration value gsl_CONFIG_CONTRACT_VIOLATION_TERMINATES=" gsl_STRINGIFY(gsl_CONFIG_CONTRACT_VIOLATION_TERMINATES) "; macro must be defined without value") +# endif +#endif +#if defined( gsl_CONFIG_CONTRACT_VIOLATION_ASSERTS ) +# if ! gsl_CHECK_CFG_NO_VALUE_( gsl_CONFIG_CONTRACT_VIOLATION_ASSERTS ) +# pragma message (__FILE__ "(" gsl_STRINGIFY( __LINE__ ) "): warning: invalid configuration value gsl_CONFIG_CONTRACT_VIOLATION_ASSERTS=" gsl_STRINGIFY(gsl_CONFIG_CONTRACT_VIOLATION_ASSERTS) "; macro must be defined without value") +# endif +#endif +#if defined( gsl_CONFIG_CONTRACT_VIOLATION_TRAPS ) +# if ! gsl_CHECK_CFG_NO_VALUE_( gsl_CONFIG_CONTRACT_VIOLATION_TRAPS ) +# pragma message (__FILE__ "(" gsl_STRINGIFY( __LINE__ ) "): warning: invalid configuration value gsl_CONFIG_CONTRACT_VIOLATION_TRAPS=" gsl_STRINGIFY(gsl_CONFIG_CONTRACT_VIOLATION_TRAPS) "; macro must be defined without value") +# endif +#endif +#if defined( gsl_CONFIG_CONTRACT_VIOLATION_CALLS_HANDLER ) +# if ! gsl_CHECK_CFG_NO_VALUE_( gsl_CONFIG_CONTRACT_VIOLATION_CALLS_HANDLER ) +# pragma message (__FILE__ "(" gsl_STRINGIFY( __LINE__ ) "): warning: invalid configuration value gsl_CONFIG_CONTRACT_VIOLATION_CALLS_HANDLER=" gsl_STRINGIFY(gsl_CONFIG_CONTRACT_VIOLATION_CALLS_HANDLER) "; macro must be defined without value") +# endif +#endif +#if defined( gsl_CONFIG_DEVICE_CONTRACT_VIOLATION_ASSERTS ) +# if ! gsl_CHECK_CFG_NO_VALUE_( gsl_CONFIG_DEVICE_CONTRACT_VIOLATION_ASSERTS ) +# pragma message (__FILE__ "(" gsl_STRINGIFY( __LINE__ ) "): warning: invalid configuration value gsl_CONFIG_DEVICE_CONTRACT_VIOLATION_ASSERTS=" gsl_STRINGIFY(gsl_CONFIG_DEVICE_CONTRACT_VIOLATION_ASSERTS) "; macro must be defined without value") +# endif +#endif +#if defined( gsl_CONFIG_DEVICE_CONTRACT_VIOLATION_TRAPS ) +# if ! gsl_CHECK_CFG_NO_VALUE_( gsl_CONFIG_DEVICE_CONTRACT_VIOLATION_TRAPS ) +# pragma message (__FILE__ "(" gsl_STRINGIFY( __LINE__ ) "): warning: invalid configuration value gsl_CONFIG_DEVICE_CONTRACT_VIOLATION_TRAPS=" gsl_STRINGIFY(gsl_CONFIG_DEVICE_CONTRACT_VIOLATION_TRAPS) "; macro must be defined without value") +# endif +#endif +#if defined( gsl_CONFIG_DEVICE_CONTRACT_VIOLATION_CALLS_HANDLER ) +# if ! gsl_CHECK_CFG_NO_VALUE_( gsl_CONFIG_DEVICE_CONTRACT_VIOLATION_CALLS_HANDLER ) +# pragma message (__FILE__ "(" gsl_STRINGIFY( __LINE__ ) "): warning: invalid configuration value gsl_CONFIG_DEVICE_CONTRACT_VIOLATION_CALLS_HANDLER=" gsl_STRINGIFY(gsl_CONFIG_DEVICE_CONTRACT_VIOLATION_CALLS_HANDLER) "; macro must be defined without value") +# endif +#endif +#if defined( gsl_CONFIG_UNENFORCED_CONTRACTS_ASSUME ) +# if ! gsl_CHECK_CFG_NO_VALUE_( gsl_CONFIG_UNENFORCED_CONTRACTS_ASSUME ) +# pragma message (__FILE__ "(" gsl_STRINGIFY( __LINE__ ) "): warning: invalid configuration value gsl_CONFIG_UNENFORCED_CONTRACTS_ASSUME=" gsl_STRINGIFY(gsl_CONFIG_UNENFORCED_CONTRACTS_ASSUME) "; macro must be defined without value") +# endif +#endif +#if defined( gsl_CONFIG_UNENFORCED_CONTRACTS_ELIDE ) +# if ! gsl_CHECK_CFG_NO_VALUE_( gsl_CONFIG_UNENFORCED_CONTRACTS_ELIDE ) +# pragma message (__FILE__ "(" gsl_STRINGIFY( __LINE__ ) "): warning: invalid configuration value gsl_CONFIG_UNENFORCED_CONTRACTS_ELIDE=" gsl_STRINGIFY(gsl_CONFIG_UNENFORCED_CONTRACTS_ELIDE) "; macro must be defined without value") +# endif +#endif +#if defined( gsl_CONFIG_DEVICE_UNENFORCED_CONTRACTS_ASSUME ) +# if ! gsl_CHECK_CFG_NO_VALUE_( gsl_CONFIG_DEVICE_UNENFORCED_CONTRACTS_ASSUME ) +# pragma message (__FILE__ "(" gsl_STRINGIFY( __LINE__ ) "): warning: invalid configuration value gsl_CONFIG_DEVICE_UNENFORCED_CONTRACTS_ASSUME=" gsl_STRINGIFY(gsl_CONFIG_DEVICE_UNENFORCED_CONTRACTS_ASSUME) "; macro must be defined without value") +# endif +#endif +#if defined( gsl_CONFIG_DEVICE_UNENFORCED_CONTRACTS_ELIDE ) +# if ! gsl_CHECK_CFG_NO_VALUE_( gsl_CONFIG_DEVICE_UNENFORCED_CONTRACTS_ELIDE ) +# pragma message (__FILE__ "(" gsl_STRINGIFY( __LINE__ ) "): warning: invalid configuration value gsl_CONFIG_DEVICE_UNENFORCED_CONTRACTS_ELIDE=" gsl_STRINGIFY(gsl_CONFIG_DEVICE_UNENFORCED_CONTRACTS_ELIDE) "; macro must be defined without value") +# endif +#endif + +#if defined( gsl_CONFIG_DEVICE_CONTRACT_VIOLATION_THROWS ) +# error cannot use gsl_CONFIG_DEVICE_CONTRACT_VIOLATION_THROWS because exceptions are not supported in device code; use gsl_CONFIG_DEVICE_CONTRACT_VIOLATION_ASSERTS or gsl_CONFIG_DEVICE_CONTRACT_VIOLATION_TRAPS +#endif +#if defined( gsl_CONFIG_DEVICE_CONTRACT_VIOLATION_TERMINATES ) +# error gsl_CONFIG_DEVICE_CONTRACT_VIOLATION_TERMINATES is not supported; use gsl_CONFIG_DEVICE_CONTRACT_VIOLATION_ASSERTS or gsl_CONFIG_DEVICE_CONTRACT_VIOLATION_TRAPS +#endif + +#if 1 < defined( gsl_CONFIG_CONTRACT_CHECKING_AUDIT ) + defined( gsl_CONFIG_CONTRACT_CHECKING_ON ) + defined( gsl_CONFIG_CONTRACT_CHECKING_OFF ) +# error only one of gsl_CONFIG_CONTRACT_CHECKING_AUDIT, gsl_CONFIG_CONTRACT_CHECKING_ON, and gsl_CONFIG_CONTRACT_CHECKING_OFF may be defined +#endif +#if 1 < defined( gsl_CONFIG_DEVICE_CONTRACT_CHECKING_AUDIT ) + defined( gsl_CONFIG_DEVICE_CONTRACT_CHECKING_ON ) + defined( gsl_CONFIG_DEVICE_CONTRACT_CHECKING_OFF ) +# error only one of gsl_CONFIG_DEVICE_CONTRACT_CHECKING_AUDIT, gsl_CONFIG_DEVICE_CONTRACT_CHECKING_ON, and gsl_CONFIG_DEVICE_CONTRACT_CHECKING_OFF may be defined +#endif +#if 1 < defined( gsl_CONFIG_CONTRACT_VIOLATION_THROWS ) + defined( gsl_CONFIG_CONTRACT_VIOLATION_TERMINATES ) + defined( gsl_CONFIG_CONTRACT_VIOLATION_ASSERTS ) + defined( gsl_CONFIG_CONTRACT_VIOLATION_TRAPS ) + defined( gsl_CONFIG_CONTRACT_VIOLATION_CALLS_HANDLER ) +# error only one of gsl_CONFIG_CONTRACT_VIOLATION_THROWS, gsl_CONFIG_CONTRACT_VIOLATION_TERMINATES, gsl_CONFIG_CONTRACT_VIOLATION_ASSERTS, gsl_CONFIG_CONTRACT_VIOLATION_TRAPS, and gsl_CONFIG_CONTRACT_VIOLATION_CALLS_HANDLER may be defined +#endif +#if 1 < defined( gsl_CONFIG_DEVICE_CONTRACT_VIOLATION_ASSERTS ) + defined( gsl_CONFIG_DEVICE_CONTRACT_VIOLATION_TRAPS ) + defined( gsl_CONFIG_DEVICE_CONTRACT_VIOLATION_CALLS_HANDLER ) +# error only one of gsl_CONFIG_DEVICE_CONTRACT_VIOLATION_ASSERTS, gsl_CONFIG_DEVICE_CONTRACT_VIOLATION_TRAPS, and gsl_CONFIG_DEVICE_CONTRACT_VIOLATION_CALLS_HANDLER may be defined +#endif +#if 1 < defined( gsl_CONFIG_UNENFORCED_CONTRACTS_ASSUME ) + defined( gsl_CONFIG_UNENFORCED_CONTRACTS_ELIDE ) +# error only one of gsl_CONFIG_UNENFORCED_CONTRACTS_ASSUME and gsl_CONFIG_UNENFORCED_CONTRACTS_ELIDE may be defined +#endif +#if 1 < defined( gsl_CONFIG_DEVICE_UNENFORCED_CONTRACTS_ASSUME ) + defined( gsl_CONFIG_DEVICE_UNENFORCED_CONTRACTS_ELIDE ) +# error only one of gsl_CONFIG_DEVICE_UNENFORCED_CONTRACTS_ASSUME and gsl_CONFIG_UNENFORCED_DEVICE_CONTRACTS_ELIDE may be defined +#endif + +#if 0 == defined( gsl_CONFIG_CONTRACT_CHECKING_AUDIT ) + defined( gsl_CONFIG_CONTRACT_CHECKING_ON ) + defined( gsl_CONFIG_CONTRACT_CHECKING_OFF ) +// select default +# define gsl_CONFIG_CONTRACT_CHECKING_ON +#endif +#if 0 == defined( gsl_CONFIG_DEVICE_CONTRACT_CHECKING_AUDIT ) + defined( gsl_CONFIG_DEVICE_CONTRACT_CHECKING_ON ) + defined( gsl_CONFIG_DEVICE_CONTRACT_CHECKING_OFF ) +// select default +# if defined( gsl_CONFIG_CONTRACT_CHECKING_AUDIT ) +# define gsl_CONFIG_DEVICE_CONTRACT_CHECKING_AUDIT +# elif defined( gsl_CONFIG_CONTRACT_CHECKING_OFF ) +# define gsl_CONFIG_DEVICE_CONTRACT_CHECKING_OFF +# else +# define gsl_CONFIG_DEVICE_CONTRACT_CHECKING_ON +# endif +#endif +#if 0 == defined( gsl_CONFIG_CONTRACT_VIOLATION_THROWS ) + defined( gsl_CONFIG_CONTRACT_VIOLATION_TERMINATES ) + defined( gsl_CONFIG_CONTRACT_VIOLATION_ASSERTS ) + defined( gsl_CONFIG_CONTRACT_VIOLATION_TRAPS ) + defined( gsl_CONFIG_CONTRACT_VIOLATION_CALLS_HANDLER ) +// select default +# if gsl_CONFIG_DEFAULTS_VERSION >= 1 +# define gsl_CONFIG_CONTRACT_VIOLATION_ASSERTS // version-1 default +# else // gsl_CONFIG_DEFAULTS_VERSION == 0 +# define gsl_CONFIG_CONTRACT_VIOLATION_TERMINATES // version-0 default +# endif // gsl_CONFIG_DEFAULTS_VERSION >= 1 +#endif +#if 0 == defined( gsl_CONFIG_DEVICE_CONTRACT_VIOLATION_ASSERTS ) + defined( gsl_CONFIG_DEVICE_CONTRACT_VIOLATION_TRAPS ) + defined( gsl_CONFIG_DEVICE_CONTRACT_VIOLATION_CALLS_HANDLER ) +// select default +# if defined( gsl_CONFIG_CONTRACT_VIOLATION_CALLS_HANDLER ) +# define gsl_CONFIG_DEVICE_CONTRACT_VIOLATION_CALLS_HANDLER +# elif defined( gsl_CONFIG_CONTRACT_VIOLATION_TRAPS ) +# define gsl_CONFIG_DEVICE_CONTRACT_VIOLATION_TRAPS +# else +# define gsl_CONFIG_DEVICE_CONTRACT_VIOLATION_ASSERTS +# endif +#endif +#if 0 == defined( gsl_CONFIG_UNENFORCED_CONTRACTS_ASSUME ) + defined( gsl_CONFIG_UNENFORCED_CONTRACTS_ELIDE ) +// select default +# define gsl_CONFIG_UNENFORCED_CONTRACTS_ELIDE +#endif +#if 0 == defined( gsl_CONFIG_DEVICE_UNENFORCED_CONTRACTS_ASSUME ) + defined( gsl_CONFIG_DEVICE_UNENFORCED_CONTRACTS_ELIDE ) +// select default +# if defined( gsl_CONFIG_UNENFORCED_CONTRACTS_ASSUME ) +# define gsl_CONFIG_DEVICE_UNENFORCED_CONTRACTS_ASSUME +# else +# define gsl_CONFIG_DEVICE_UNENFORCED_CONTRACTS_ELIDE +# endif +#endif + +// C++ language version detection: +// Note: VC14.0/1900 (VS2015) lacks too much from C++14. + +#ifndef gsl_CPLUSPLUS +# if defined(_MSVC_LANG ) && !defined(__clang__) +# define gsl_CPLUSPLUS (_MSC_VER == 1900 ? 201103L : _MSVC_LANG ) +# else +# define gsl_CPLUSPLUS __cplusplus +# endif +#endif + +// C++ standard library version: + +#ifndef gsl_CPLUSPLUS_STDLIB +# define gsl_CPLUSPLUS_STDLIB gsl_CPLUSPLUS +#endif + +#define gsl_CPP98_OR_GREATER ( gsl_CPLUSPLUS >= 199711L ) +#define gsl_CPP11_OR_GREATER ( gsl_CPLUSPLUS >= 201103L ) +#define gsl_CPP14_OR_GREATER ( gsl_CPLUSPLUS >= 201402L ) +#define gsl_CPP17_OR_GREATER ( gsl_CPLUSPLUS >= 201703L ) +#define gsl_CPP20_OR_GREATER ( gsl_CPLUSPLUS >= 202002L ) +#define gsl_CPP23_OR_GREATER ( gsl_CPLUSPLUS >= 202302L ) +#define gsl_CPP26_OR_GREATER ( gsl_CPLUSPLUS > 202302L ) // not finalized yet + +// C++ language version (represent 98 as 3): + +#define gsl_CPLUSPLUS_V ( gsl_CPLUSPLUS / 100 - (gsl_CPLUSPLUS > 200000 ? 2000 : 1994) ) + +// half-open range [lo..hi): +#define gsl_BETWEEN( v, lo, hi ) ( (lo) <= (v) && (v) < (hi) ) + +// Compiler versions: + +// MSVC++ 6.0 _MSC_VER == 1200 gsl_COMPILER_MSVC_VERSION == 60 (Visual Studio 6.0) +// MSVC++ 7.0 _MSC_VER == 1300 gsl_COMPILER_MSVC_VERSION == 70 (Visual Studio .NET 2002) +// MSVC++ 7.1 _MSC_VER == 1310 gsl_COMPILER_MSVC_VERSION == 71 (Visual Studio .NET 2003) +// MSVC++ 8.0 _MSC_VER == 1400 gsl_COMPILER_MSVC_VERSION == 80 (Visual Studio 2005) +// MSVC++ 9.0 _MSC_VER == 1500 gsl_COMPILER_MSVC_VERSION == 90 (Visual Studio 2008) +// MSVC++ 10.0 _MSC_VER == 1600 gsl_COMPILER_MSVC_VERSION == 100 (Visual Studio 2010) +// MSVC++ 11.0 _MSC_VER == 1700 gsl_COMPILER_MSVC_VERSION == 110 (Visual Studio 2012) +// MSVC++ 12.0 _MSC_VER == 1800 gsl_COMPILER_MSVC_VERSION == 120 (Visual Studio 2013) +// MSVC++ 14.0 _MSC_VER == 1900 gsl_COMPILER_MSVC_VERSION == 140 (Visual Studio 2015) +// MSVC++ 14.1 _MSC_VER >= 1910 gsl_COMPILER_MSVC_VERSION == 141 (Visual Studio 2017) +// MSVC++ 14.2 _MSC_VER >= 1920 gsl_COMPILER_MSVC_VERSION == 142 (Visual Studio 2019) +// MSVC++ 14.3 _MSC_VER >= 1930 gsl_COMPILER_MSVC_VERSION == 143 (Visual Studio 2022) + +#if defined( _MSC_VER ) && ! defined( __clang__ ) +# define gsl_COMPILER_MSVC_VER (_MSC_VER ) +# define gsl_COMPILER_MSVC_VERSION (_MSC_VER / 10 - 10 * ( 5 + (_MSC_VER < 1900 ) ) ) +# define gsl_COMPILER_MSVC_VERSION_FULL (_MSC_VER - 100 * ( 5 + (_MSC_VER < 1900 ) ) ) +#else +# define gsl_COMPILER_MSVC_VER 0 +# define gsl_COMPILER_MSVC_VERSION 0 +# define gsl_COMPILER_MSVC_VERSION_FULL 0 +#endif + +#define gsl_COMPILER_VERSION( major, minor, patch ) ( 10 * ( 10 * (major) + (minor) ) + (patch) ) + +// AppleClang 7.0.0 __apple_build_version__ == 7000172 gsl_COMPILER_APPLECLANG_VERSION == 700 (Xcode 7.0, 7.0.1) (LLVM 3.7.0) +// AppleClang 7.0.0 __apple_build_version__ == 7000176 gsl_COMPILER_APPLECLANG_VERSION == 700 (Xcode 7.1) (LLVM 3.7.0) +// AppleClang 7.0.2 __apple_build_version__ == 7000181 gsl_COMPILER_APPLECLANG_VERSION == 702 (Xcode 7.2, 7.2.1) (LLVM 3.7.0) +// AppleClang 7.3.0 __apple_build_version__ == 7030029 gsl_COMPILER_APPLECLANG_VERSION == 730 (Xcode 7.3) (LLVM 3.8.0) +// AppleClang 7.3.0 __apple_build_version__ == 7030031 gsl_COMPILER_APPLECLANG_VERSION == 730 (Xcode 7.3.1) (LLVM 3.8.0) +// AppleClang 8.0.0 __apple_build_version__ == 8000038 gsl_COMPILER_APPLECLANG_VERSION == 800 (Xcode 8.0) (LLVM 3.9.0) +// AppleClang 8.0.0 __apple_build_version__ == 8000042 gsl_COMPILER_APPLECLANG_VERSION == 800 (Xcode 8.1, 8.2, 8.2.1) (LLVM 3.9.0) +// AppleClang 8.1.0 __apple_build_version__ == 8020038 gsl_COMPILER_APPLECLANG_VERSION == 810 (Xcode 8.3) (LLVM 3.9.0) +// AppleClang 8.1.0 __apple_build_version__ == 8020041 gsl_COMPILER_APPLECLANG_VERSION == 810 (Xcode 8.3.1) (LLVM 3.9.0) +// AppleClang 8.1.0 __apple_build_version__ == 8020042 gsl_COMPILER_APPLECLANG_VERSION == 810 (Xcode 8.3.2, 8.3.3) (LLVM 3.9.0) +// AppleClang 9.0.0 __apple_build_version__ == 9000037 gsl_COMPILER_APPLECLANG_VERSION == 900 (Xcode 9.0) (LLVM 4.0.0) +// AppleClang 9.0.0 __apple_build_version__ == 9000038 gsl_COMPILER_APPLECLANG_VERSION == 900 (Xcode 9.1) (LLVM 4.0.0) +// AppleClang 9.0.0 __apple_build_version__ == 9000039 gsl_COMPILER_APPLECLANG_VERSION == 900 (Xcode 9.2) (LLVM 4.0.0) +// AppleClang 9.1.0 __apple_build_version__ == 9020039 gsl_COMPILER_APPLECLANG_VERSION == 910 (Xcode 9.3, 9.3.1) (LLVM 5.0.2) +// AppleClang 9.1.0 __apple_build_version__ == 9020039 gsl_COMPILER_APPLECLANG_VERSION == 910 (Xcode 9.4, 9.4.1) (LLVM 5.0.2) +// AppleClang 10.0.0 __apple_build_version__ == 10001145 gsl_COMPILER_APPLECLANG_VERSION == 1000 (Xcode 10.0, 10.1) (LLVM 6.0.1) +// AppleClang 10.0.1 __apple_build_version__ == 10010046 gsl_COMPILER_APPLECLANG_VERSION == 1001 (Xcode 10.2, 10.2.1, 10.3) (LLVM 7.0.0) +// AppleClang 11.0.0 __apple_build_version__ == 11000033 gsl_COMPILER_APPLECLANG_VERSION == 1100 (Xcode 11.1, 11.2, 11.3, 11.3.1) (LLVM 8.0.0) +// AppleClang 11.0.3 __apple_build_version__ == 11030032 gsl_COMPILER_APPLECLANG_VERSION == 1103 (Xcode 11.4, 11.4.1, 11.5, 11.6) (LLVM 9.0.0) +// AppleClang 12.0.0 __apple_build_version__ == 12000032 gsl_COMPILER_APPLECLANG_VERSION == 1200 (Xcode 12.0–12.4) (LLVM 10.0.0) +// AppleClang 12.0.5 __apple_build_version__ == 12050022 gsl_COMPILER_APPLECLANG_VERSION == 1205 (Xcode 12.5) (LLVM 11.1.0) +// AppleClang 13.0.0 __apple_build_version__ == 13000029 gsl_COMPILER_APPLECLANG_VERSION == 1300 (Xcode 13.0–13.2.1) (LLVM 12.0.0) +// AppleClang 13.1.6 __apple_build_version__ == 13160021 gsl_COMPILER_APPLECLANG_VERSION == 1316 (Xcode 13.3–13.4.1) (LLVM 13.0.0) +// AppleClang 14.0.0 __apple_build_version__ == 14000029 gsl_COMPILER_APPLECLANG_VERSION == 1400 (Xcode 14.0–14.2) (LLVM 14.0.0) +// AppleClang 14.0.3 __apple_build_version__ == 14030022 gsl_COMPILER_APPLECLANG_VERSION == 1403 (Xcode 14.3) (LLVM 15.0.0) +// AppleClang 15.0.0 __apple_build_version__ == 15000040 gsl_COMPILER_APPLECLANG_VERSION == 1500 (Xcode 15.0) (LLVM 16.0.0) +// AppleClang 15.0.0 __apple_build_version__ == 15000100 gsl_COMPILER_APPLECLANG_VERSION == 1500 (Xcode 15.1–15.2) (LLVM 16.0.0) +// AppleClang 15.0.0 __apple_build_version__ == 15000309 gsl_COMPILER_APPLECLANG_VERSION == 1500 (Xcode 15.3–15.4) (LLVM 16.0.0) +// AppleClang 16.0.0 __apple_build_version__ == 16000026 gsl_COMPILER_APPLECLANG_VERSION == 1600 (Xcode 16.0–16.2) (LLVM 17.0.6) +// AppleClang 17.0.0 __apple_build_version__ == 17000013 gsl_COMPILER_APPLECLANG_VERSION == 1700 (Xcode 16.3) (LLVM 19.1.4) +// AppleClang 17.0.0 __apple_build_version__ == 17000013 gsl_COMPILER_APPLECLANG_VERSION == 1700 (Xcode 16.4) (LLVM 19.1.5) + +#if defined( __apple_build_version__ ) +# define gsl_COMPILER_APPLECLANG_VERSION gsl_COMPILER_VERSION( __clang_major__, __clang_minor__, __clang_patchlevel__ ) +# define gsl_COMPILER_CLANG_VERSION 0 +#elif defined( __clang__ ) +# define gsl_COMPILER_APPLECLANG_VERSION 0 +# define gsl_COMPILER_CLANG_VERSION gsl_COMPILER_VERSION( __clang_major__, __clang_minor__, __clang_patchlevel__ ) +#else +# define gsl_COMPILER_APPLECLANG_VERSION 0 +# define gsl_COMPILER_CLANG_VERSION 0 +#endif + +#if defined( __GNUC__ ) && ! defined( __clang__ ) && ! defined( __NVCOMPILER ) +# define gsl_COMPILER_GNUC_VERSION gsl_COMPILER_VERSION( __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__ ) +#else +# define gsl_COMPILER_GNUC_VERSION 0 +#endif + +#if defined( __NVCC__ ) +# define gsl_COMPILER_NVCC_VERSION ( __CUDACC_VER_MAJOR__ * 10 + __CUDACC_VER_MINOR__ ) +#else +# define gsl_COMPILER_NVCC_VERSION 0 +#endif + +// NVHPC 21.2 gsl_COMPILER_NVHPC_VERSION == 2120 +#if defined( __NVCOMPILER ) +# define gsl_COMPILER_NVHPC_VERSION gsl_COMPILER_VERSION( __NVCOMPILER_MAJOR__, __NVCOMPILER_MINOR__, __NVCOMPILER_PATCHLEVEL__ ) +#else +# define gsl_COMPILER_NVHPC_VERSION 0 +#endif + +#if defined( __ARMCC_VERSION ) +# define gsl_COMPILER_ARMCC_VERSION ( __ARMCC_VERSION / 10000 ) +# define gsl_COMPILER_ARMCC_VERSION_FULL __ARMCC_VERSION +#else +# define gsl_COMPILER_ARMCC_VERSION 0 +# define gsl_COMPILER_ARMCC_VERSION_FULL 0 +#endif + + +// Compiler non-strict aliasing: + +#if defined(__clang__) || defined(__GNUC__) +# define gsl_may_alias __attribute__((__may_alias__)) +#else +# define gsl_may_alias +#endif + +// Presence of gsl, language and library features: + +#define gsl_IN_STD( v ) ( ((v) == 98 ? 3 : (v)) >= gsl_CPLUSPLUS_V ) + +#define gsl_DEPRECATE_TO_LEVEL( level ) ( level <= gsl_CONFIG_DEPRECATE_TO_LEVEL ) +#define gsl_FEATURE_TO_STD( feature ) gsl_IN_STD( gsl_FEATURE( feature##_TO_STD ) ) +#define gsl_FEATURE( feature ) gsl_EVALF_( gsl_FEATURE_##feature##_ ) +#define gsl_CONFIG( feature ) gsl_EVALF_( gsl_CONFIG_##feature##_ ) +#define gsl_HAVE( feature ) gsl_EVALF_( gsl_HAVE_##feature##_ ) + +// Presence of wide character support: + +#if defined(__DJGPP__) || (defined(_LIBCPP_VERSION) && defined(_LIBCPP_HAS_NO_WIDE_CHARACTERS)) +# define gsl_HAVE_WCHAR 0 +#else +# define gsl_HAVE_WCHAR 1 +#endif +#define gsl_HAVE_WCHAR_() gsl_HAVE_WCHAR + +// Compiling device code: + +#if defined( __CUDACC__ ) && defined( __CUDA_ARCH__ ) +# define gsl_DEVICE_CODE 1 +#else +# define gsl_DEVICE_CODE 0 +#endif + + +// Presence of language & library features: + +#if gsl_COMPILER_CLANG_VERSION || gsl_COMPILER_APPLECLANG_VERSION +# ifdef __OBJC__ + // There are a bunch of inconsistencies about __EXCEPTIONS and __has_feature(cxx_exceptions) in Clang 3.4/3.5/3.6. + // We're interested in C++ exceptions, which can be checked by __has_feature(cxx_exceptions) in 3.5+. + // In pre-3.5, __has_feature(cxx_exceptions) can be true if ObjC exceptions are enabled, but C++ exceptions are disabled. + // The recommended way to check is `__EXCEPTIONS && __has_feature(cxx_exceptions)`. + // See https://releases.llvm.org/3.6.0/tools/clang/docs/ReleaseNotes.html#the-exceptions-macro + // Note: this is only relevant in Objective-C++, thus the ifdef. +# if __EXCEPTIONS && __has_feature(cxx_exceptions) +# define gsl_HAVE_EXCEPTIONS 1 +# else +# define gsl_HAVE_EXCEPTIONS 0 +# endif // __EXCEPTIONS && __has_feature(cxx_exceptions) +# else + // clang-cl doesn't define __EXCEPTIONS for MSVC compatibility (see https://reviews.llvm.org/D4065). + // Neither does Clang in MS-compatiblity mode. + // Let's hope no one tries to build Objective-C++ code using MS-compatibility mode or clang-cl. +# if __has_feature(cxx_exceptions) +# define gsl_HAVE_EXCEPTIONS 1 +# else +# define gsl_HAVE_EXCEPTIONS 0 +# endif +# endif +#elif defined( __GNUC__ ) +# if __GNUC__ < 5 +# ifdef __EXCEPTIONS +# define gsl_HAVE_EXCEPTIONS 1 +# else +# define gsl_HAVE_EXCEPTIONS 0 +# endif // __EXCEPTIONS +# else +# ifdef __cpp_exceptions +# define gsl_HAVE_EXCEPTIONS 1 +# else +# define gsl_HAVE_EXCEPTIONS 0 +# endif // __cpp_exceptions +# endif // __GNUC__ < 5 +#elif gsl_COMPILER_MSVC_VERSION +# ifdef _CPPUNWIND +# define gsl_HAVE_EXCEPTIONS 1 +# else +# define gsl_HAVE_EXCEPTIONS 0 +# endif // _CPPUNWIND +#else +// For all other compilers, assume exceptions are always enabled. +# define gsl_HAVE_EXCEPTIONS 1 +#endif +#define gsl_HAVE_EXCEPTIONS_() gsl_HAVE_EXCEPTIONS + +#if defined( gsl_CONFIG_CONTRACT_VIOLATION_THROWS ) && ! gsl_HAVE( EXCEPTIONS ) +# error Cannot use gsl_CONFIG_CONTRACT_VIOLATION_THROWS if exceptions are disabled. +#endif // defined( gsl_CONFIG_CONTRACT_VIOLATION_THROWS ) && !gsl_HAVE( EXCEPTIONS ) + +#ifdef _HAS_CPP0X +# define gsl_HAS_CPP0X _HAS_CPP0X +#else +# define gsl_HAS_CPP0X 0 +#endif + +#define gsl_CPP11_100 (gsl_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VER >= 1600) +#define gsl_CPP11_110 (gsl_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VER >= 1700) +#define gsl_CPP11_120 (gsl_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VER >= 1800) +#define gsl_CPP11_140 (gsl_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VER >= 1900) + +#define gsl_CPP14_000 (gsl_CPP14_OR_GREATER) +#define gsl_CPP14_120 (gsl_CPP14_OR_GREATER || gsl_COMPILER_MSVC_VER >= 1800) +#define gsl_CPP14_140 (gsl_CPP14_OR_GREATER || gsl_COMPILER_MSVC_VER >= 1900) + +#define gsl_CPP17_000 (gsl_CPP17_OR_GREATER) +#define gsl_CPP17_140 (gsl_CPP17_OR_GREATER || gsl_COMPILER_MSVC_VER >= 1900) + +#define gsl_CPP11_140_CPP0X_90 (gsl_CPP11_140 || (gsl_COMPILER_MSVC_VER >= 1500 && gsl_HAS_CPP0X)) +#define gsl_CPP11_140_CPP0X_100 (gsl_CPP11_140 || (gsl_COMPILER_MSVC_VER >= 1600 && gsl_HAS_CPP0X)) + +// Presence of C++11 language features: + +#define gsl_HAVE_C99_PREPROCESSOR gsl_CPP11_140 +#define gsl_HAVE_AUTO gsl_CPP11_100 +#define gsl_HAVE_RVALUE_REFERENCE gsl_CPP11_100 +#define gsl_HAVE_FUNCTION_REF_QUALIFIER ( gsl_CPP11_140 && ! gsl_BETWEEN( gsl_COMPILER_GNUC_VERSION, 1, 481 ) ) +#define gsl_HAVE_ENUM_CLASS gsl_CPP11_110 +#define gsl_HAVE_ALIAS_TEMPLATE gsl_CPP11_120 +#define gsl_HAVE_DEFAULT_FUNCTION_TEMPLATE_ARG gsl_CPP11_120 +#define gsl_HAVE_EXPLICIT gsl_CPP11_120 +#define gsl_HAVE_VARIADIC_TEMPLATE gsl_CPP11_120 +#define gsl_HAVE_IS_DELETE gsl_CPP11_120 +#define gsl_HAVE_CONSTEXPR_11 gsl_CPP11_140 +#define gsl_HAVE_IS_DEFAULT gsl_CPP11_140 +#define gsl_HAVE_NOEXCEPT gsl_CPP11_140 +#define gsl_HAVE_NORETURN ( gsl_CPP11_140 && ! gsl_BETWEEN( gsl_COMPILER_GNUC_VERSION, 1, 480 ) ) +#define gsl_HAVE_EXPRESSION_SFINAE gsl_CPP11_140 +#define gsl_HAVE_OVERRIDE_FINAL gsl_CPP11_110 + +#define gsl_HAVE_C99_PREPROCESSOR_() gsl_HAVE_C99_PREPROCESSOR +#define gsl_HAVE_AUTO_() gsl_HAVE_AUTO +#define gsl_HAVE_RVALUE_REFERENCE_() gsl_HAVE_RVALUE_REFERENCE +#define gsl_HAVE_FUNCTION_REF_QUALIFIER_() gsl_HAVE_FUNCTION_REF_QUALIFIER +#define gsl_HAVE_ENUM_CLASS_() gsl_HAVE_ENUM_CLASS +#define gsl_HAVE_ALIAS_TEMPLATE_() gsl_HAVE_ALIAS_TEMPLATE +#define gsl_HAVE_DEFAULT_FUNCTION_TEMPLATE_ARG_() gsl_HAVE_DEFAULT_FUNCTION_TEMPLATE_ARG +#define gsl_HAVE_EXPLICIT_() gsl_HAVE_EXPLICIT +#define gsl_HAVE_VARIADIC_TEMPLATE_() gsl_HAVE_VARIADIC_TEMPLATE +#define gsl_HAVE_IS_DELETE_() gsl_HAVE_IS_DELETE +#define gsl_HAVE_CONSTEXPR_11_() gsl_HAVE_CONSTEXPR_11 +#define gsl_HAVE_IS_DEFAULT_() gsl_HAVE_IS_DEFAULT +#define gsl_HAVE_NOEXCEPT_() gsl_HAVE_NOEXCEPT +#define gsl_HAVE_NORETURN_() gsl_HAVE_NORETURN +#define gsl_HAVE_EXPRESSION_SFINAE_() gsl_HAVE_EXPRESSION_SFINAE +#define gsl_HAVE_OVERRIDE_FINAL_() gsl_HAVE_OVERRIDE_FINAL + +// Presence of C++14 language features: + +#define gsl_HAVE_CONSTEXPR_14 ( gsl_CPP14_000 && ! gsl_BETWEEN( gsl_COMPILER_GNUC_VERSION, 1, 600 ) ) +#define gsl_HAVE_DECLTYPE_AUTO gsl_CPP14_140 +#define gsl_HAVE_DEPRECATED ( gsl_CPP14_140 && ! gsl_BETWEEN( gsl_COMPILER_MSVC_VERSION, 1, 142 ) ) + +#define gsl_HAVE_CONSTEXPR_14_() gsl_HAVE_CONSTEXPR_14 +#define gsl_HAVE_DECLTYPE_AUTO_() gsl_HAVE_DECLTYPE_AUTO +#define gsl_HAVE_DEPRECATED_() gsl_HAVE_DEPRECATED + +// Presence of C++17 language features: +// MSVC: template parameter deduction guides since Visual Studio 2017 v15.7 + +#define gsl_HAVE_ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE gsl_CPP17_000 +#define gsl_HAVE_DEDUCTION_GUIDES ( gsl_CPP17_000 && ! gsl_BETWEEN( gsl_COMPILER_MSVC_VERSION_FULL, 1, 1414 ) ) +#define gsl_HAVE_NODISCARD gsl_CPP17_000 +#define gsl_HAVE_CONSTEXPR_17 gsl_CPP17_OR_GREATER + +#define gsl_HAVE_ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE_() gsl_HAVE_ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE +#define gsl_HAVE_DEDUCTION_GUIDES_() gsl_HAVE_DEDUCTION_GUIDES +#define gsl_HAVE_NODISCARD_() gsl_HAVE_NODISCARD +#define gsl_HAVE_MAYBE_UNUSED_() gsl_CPP17_OR_GREATER +#define gsl_HAVE_CONSTEXPR_17_() gsl_HAVE_CONSTEXPR_17 + +// Presence of C++20 language features: + +#define gsl_HAVE_CONSTEXPR_20 gsl_CPP20_OR_GREATER +#define gsl_HAVE_CONSTEXPR_20_() gsl_HAVE_CONSTEXPR_20 + +// Presence of C++23 language features: + +#define gsl_HAVE_CONSTEXPR_23 gsl_CPP23_OR_GREATER +#define gsl_HAVE_CONSTEXPR_23_() gsl_HAVE_CONSTEXPR_23 + +// Presence of C++26 language features: + +#define gsl_HAVE_CONSTEXPR_26 gsl_CPP26_OR_GREATER +#define gsl_HAVE_CONSTEXPR_26_() gsl_HAVE_CONSTEXPR_26 + +// Presence of C++ library features: + +#if gsl_BETWEEN( gsl_COMPILER_ARMCC_VERSION, 1, 600 ) +// Some versions of the ARM compiler apparently ship without a C++11 standard library despite having some C++11 support. +# define gsl_STDLIB_CPP98_OR_GREATER gsl_CPP98_OR_GREATER +# define gsl_STDLIB_CPP11_OR_GREATER 0 +# define gsl_STDLIB_CPP14_OR_GREATER 0 +# define gsl_STDLIB_CPP17_OR_GREATER 0 +# define gsl_STDLIB_CPP20_OR_GREATER 0 +# define gsl_STDLIB_CPP23_OR_GREATER 0 +# define gsl_STDLIB_CPP26_OR_GREATER 0 +#else +# define gsl_STDLIB_CPP98_OR_GREATER gsl_CPP98_OR_GREATER +# define gsl_STDLIB_CPP11_OR_GREATER gsl_CPP11_OR_GREATER +# define gsl_STDLIB_CPP14_OR_GREATER gsl_CPP14_OR_GREATER +# define gsl_STDLIB_CPP17_OR_GREATER gsl_CPP17_OR_GREATER +# define gsl_STDLIB_CPP20_OR_GREATER gsl_CPP20_OR_GREATER +# define gsl_STDLIB_CPP23_OR_GREATER gsl_CPP23_OR_GREATER +# define gsl_STDLIB_CPP26_OR_GREATER gsl_CPP26_OR_GREATER +#endif + +#define gsl_STDLIB_CPP11_100 (gsl_STDLIB_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VER >= 1600) +#define gsl_STDLIB_CPP11_110 (gsl_STDLIB_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VER >= 1700) +#define gsl_STDLIB_CPP11_120 (gsl_STDLIB_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VER >= 1800) +#define gsl_STDLIB_CPP11_140 (gsl_STDLIB_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VER >= 1900) + +#define gsl_STDLIB_CPP14_000 (gsl_STDLIB_CPP14_OR_GREATER) +#define gsl_STDLIB_CPP14_120 (gsl_STDLIB_CPP14_OR_GREATER || gsl_COMPILER_MSVC_VER >= 1800) +#define gsl_STDLIB_CPP14_140 (gsl_STDLIB_CPP14_OR_GREATER || gsl_COMPILER_MSVC_VER >= 1900) + +#define gsl_STDLIB_CPP17_000 (gsl_STDLIB_CPP17_OR_GREATER) +#define gsl_STDLIB_CPP17_140 (gsl_STDLIB_CPP17_OR_GREATER || gsl_COMPILER_MSVC_VER >= 1900) + +#define gsl_STDLIB_CPP11_140_CPP0X_90 (gsl_STDLIB_CPP11_140 || (gsl_COMPILER_MSVC_VER >= 1500 && gsl_HAS_CPP0X)) +#define gsl_STDLIB_CPP11_140_CPP0X_100 (gsl_STDLIB_CPP11_140 || (gsl_COMPILER_MSVC_VER >= 1600 && gsl_HAS_CPP0X)) + +#define gsl_HAVE_ADDRESSOF gsl_STDLIB_CPP17_000 +#define gsl_HAVE_ARRAY gsl_STDLIB_CPP11_110 +#define gsl_HAVE_TYPE_TRAITS gsl_STDLIB_CPP11_110 +#define gsl_HAVE_TR1_TYPE_TRAITS gsl_STDLIB_CPP11_110 +#define gsl_HAVE_CONTAINER_DATA_METHOD gsl_STDLIB_CPP11_140_CPP0X_90 +#define gsl_HAVE_STD_DATA gsl_STDLIB_CPP17_000 +#ifdef __cpp_lib_ssize +# define gsl_HAVE_STD_SSIZE 1 +#else +# define gsl_HAVE_STD_SSIZE ( gsl_COMPILER_GNUC_VERSION >= 1000 && __cplusplus > 201703L ) +#endif +#define gsl_HAVE_HASH gsl_STDLIB_CPP11_120 +#define gsl_HAVE_SIZED_TYPES gsl_STDLIB_CPP11_140 +#define gsl_HAVE_MAKE_SHARED gsl_STDLIB_CPP11_140_CPP0X_100 +#define gsl_HAVE_SHARED_PTR gsl_STDLIB_CPP11_140_CPP0X_100 +#define gsl_HAVE_UNIQUE_PTR gsl_STDLIB_CPP11_140_CPP0X_100 +#define gsl_HAVE_MAKE_UNIQUE gsl_STDLIB_CPP14_120 +#define gsl_HAVE_MOVE_FORWARD gsl_STDLIB_CPP11_100 +#define gsl_HAVE_NULLPTR gsl_STDLIB_CPP11_100 +#define gsl_HAVE_UNCAUGHT_EXCEPTIONS gsl_STDLIB_CPP17_140 +#define gsl_HAVE_ADD_CONST gsl_HAVE_TYPE_TRAITS +#define gsl_HAVE_INITIALIZER_LIST gsl_STDLIB_CPP11_120 +#define gsl_HAVE_INTEGRAL_CONSTANT gsl_HAVE_TYPE_TRAITS +#define gsl_HAVE_REMOVE_CONST gsl_HAVE_TYPE_TRAITS +#define gsl_HAVE_REMOVE_REFERENCE gsl_HAVE_TYPE_TRAITS +#define gsl_HAVE_REMOVE_CVREF gsl_STDLIB_CPP20_OR_GREATER +#define gsl_HAVE_TR1_ADD_CONST gsl_HAVE_TR1_TYPE_TRAITS +#define gsl_HAVE_TR1_INTEGRAL_CONSTANT gsl_HAVE_TR1_TYPE_TRAITS +#define gsl_HAVE_TR1_REMOVE_CONST gsl_HAVE_TR1_TYPE_TRAITS +#define gsl_HAVE_TR1_REMOVE_REFERENCE gsl_HAVE_TR1_TYPE_TRAITS + +#define gsl_HAVE_ADDRESSOF_() gsl_HAVE_ADDRESSOF +#define gsl_HAVE_ARRAY_() gsl_HAVE_ARRAY +#define gsl_HAVE_TYPE_TRAITS_() gsl_HAVE_TYPE_TRAITS +#define gsl_HAVE_TR1_TYPE_TRAITS_() gsl_HAVE_TR1_TYPE_TRAITS +#define gsl_HAVE_CONTAINER_DATA_METHOD_() gsl_HAVE_CONTAINER_DATA_METHOD +#define gsl_HAVE_HASH_() gsl_HAVE_HASH +#define gsl_HAVE_STD_DATA_() gsl_HAVE_STD_DATA +#define gsl_HAVE_STD_SSIZE_() gsl_HAVE_STD_SSIZE +#define gsl_HAVE_SIZED_TYPES_() gsl_HAVE_SIZED_TYPES +#define gsl_HAVE_MAKE_SHARED_() gsl_HAVE_MAKE_SHARED +#define gsl_HAVE_MOVE_FORWARD_() gsl_HAVE_MOVE_FORWARD +#define gsl_HAVE_NULLPTR_() gsl_HAVE_NULLPTR // It's a language feature but needs library support, so we list it as a library feature. +#define gsl_HAVE_SHARED_PTR_() gsl_HAVE_SHARED_PTR +#define gsl_HAVE_UNIQUE_PTR_() gsl_HAVE_UNIQUE_PTR +#define gsl_HAVE_MAKE_UNIQUE_() gsl_HAVE_MAKE_UNIQUE +#define gsl_HAVE_UNCAUGHT_EXCEPTIONS_() gsl_HAVE_UNCAUGHT_EXCEPTIONS +#define gsl_HAVE_ADD_CONST_() gsl_HAVE_ADD_CONST +#define gsl_HAVE_INITIALIZER_LIST_() gsl_HAVE_INITIALIZER_LIST // It's a language feature but needs library support, so we list it as a library feature. +#define gsl_HAVE_INTEGRAL_CONSTANT_() gsl_HAVE_INTEGRAL_CONSTANT +#define gsl_HAVE_REMOVE_CONST_() gsl_HAVE_REMOVE_CONST +#define gsl_HAVE_REMOVE_REFERENCE_() gsl_HAVE_REMOVE_REFERENCE +#define gsl_HAVE_REMOVE_CVREF_() gsl_HAVE_REMOVE_CVREF +#define gsl_HAVE_TR1_ADD_CONST_() gsl_HAVE_TR1_ADD_CONST +#define gsl_HAVE_TR1_INTEGRAL_CONSTANT_() gsl_HAVE_TR1_INTEGRAL_CONSTANT +#define gsl_HAVE_TR1_REMOVE_CONST_() gsl_HAVE_TR1_REMOVE_CONST +#define gsl_HAVE_TR1_REMOVE_REFERENCE_() gsl_HAVE_TR1_REMOVE_REFERENCE + +// C++ feature usage: + +#if gsl_HAVE( ADDRESSOF ) +# define gsl_ADDRESSOF(x) std::addressof(x) +#else +# define gsl_ADDRESSOF(x) (&x) +#endif + +#if gsl_HAVE( CONSTEXPR_11 ) +# define gsl_constexpr constexpr +#else +# define gsl_constexpr /*constexpr*/ +#endif + +#if gsl_HAVE( CONSTEXPR_14 ) +# define gsl_constexpr14 constexpr +#else +# define gsl_constexpr14 /*constexpr*/ +#endif + +#if gsl_HAVE( CONSTEXPR_17 ) +# define gsl_constexpr17 constexpr +#else +# define gsl_constexpr17 /*constexpr*/ +#endif + +#if gsl_HAVE( CONSTEXPR_20 ) +# define gsl_constexpr20 constexpr +#else +# define gsl_constexpr20 /*constexpr*/ +#endif + +#if gsl_HAVE( CONSTEXPR_23 ) +# define gsl_constexpr23 constexpr +#else +# define gsl_constexpr23 /*constexpr*/ +#endif + +#if gsl_HAVE( CONSTEXPR_26 ) +# define gsl_constexpr26 constexpr +#else +# define gsl_constexpr26 /*constexpr*/ +#endif + +#if gsl_HAVE( EXPLICIT ) +# define gsl_explicit explicit +#else +# define gsl_explicit /*explicit*/ +#endif + +#if gsl_HAVE( IS_DELETE ) +# define gsl_is_delete = delete +#else +# define gsl_is_delete +#endif + +#if gsl_HAVE( IS_DELETE ) +# define gsl_is_delete_access public +#else +# define gsl_is_delete_access private +#endif + +#if gsl_HAVE( NOEXCEPT ) +# define gsl_noexcept noexcept +# define gsl_noexcept_if( expr ) noexcept( expr ) +#else +# define gsl_noexcept throw() +# define gsl_noexcept_if( expr ) /*noexcept( expr )*/ +#endif +#if defined( gsl_TESTING_ ) +# define gsl_noexcept_not_testing +#else +# define gsl_noexcept_not_testing gsl_noexcept +#endif + +#if gsl_HAVE( NULLPTR ) +# define gsl_nullptr nullptr +#else +# define gsl_nullptr NULL +#endif + +#if gsl_HAVE( NODISCARD ) +# define gsl_NODISCARD [[nodiscard]] +#else +# define gsl_NODISCARD +#endif + +#if gsl_HAVE( NORETURN ) +# define gsl_NORETURN [[noreturn]] +#elif defined( _MSC_VER ) +# define gsl_NORETURN __declspec(noreturn) +#elif defined( __GNUC__ ) || gsl_COMPILER_ARMCC_VERSION +# define gsl_NORETURN __attribute__((noreturn)) +#else +# define gsl_NORETURN +#endif + +#if gsl_CPP20_OR_GREATER +# if defined( _MSC_VER ) // MSVC or MSVC-compatible compiler +# if gsl_COMPILER_MSVC_VERSION >= 1929 || gsl_COMPILER_CLANG_VERSION >= 1800 // VS2019 v16.10 and later, or Clang 18 and later +# define gsl_NO_UNIQUE_ADDRESS [[msvc::no_unique_address]] +# endif +# else // ! defined( _MSC_VER ) +# define gsl_NO_UNIQUE_ADDRESS [[no_unique_address]] +# endif // defined( _MSC_VER ) +#endif // gsl_CPP20_OR_GREATER + +#if gsl_HAVE( MAYBE_UNUSED ) +# define gsl_MAYBE_UNUSED [[maybe_unused]] +# if gsl_COMPILER_GNUC_VERSION +// GCC currently ignores the [[maybe_unused]] attribute on data members and warns accordingly (cf. https://stackoverflow.com/a/65633590). +# define gsl_MAYBE_UNUSED_MEMBER +# else // ! gsl_COMPILER_GNUC_VERSION +# define gsl_MAYBE_UNUSED_MEMBER [[maybe_unused]] +# endif // gsl_COMPILER_GNUC_VERSION +#else +# define gsl_MAYBE_UNUSED +# define gsl_MAYBE_UNUSED_MEMBER +#endif + +#if gsl_HAVE( DEPRECATED ) && ! defined( gsl_TESTING_ ) +# define gsl_DEPRECATED [[deprecated]] +# define gsl_DEPRECATED_MSG( msg ) [[deprecated( msg )]] +#else +# define gsl_DEPRECATED +# define gsl_DEPRECATED_MSG( msg ) +#endif + +#if gsl_HAVE( C99_PREPROCESSOR ) +# if gsl_CPP20_OR_GREATER +# define gsl_CONSTRAINT(...) __VA_ARGS__ +# else +# define gsl_CONSTRAINT(...) typename +# endif +#endif + +#if gsl_HAVE( TYPE_TRAITS ) +# define gsl_STATIC_ASSERT_( cond, msg ) static_assert( cond, msg ) +#else +# define gsl_STATIC_ASSERT_( cond, msg ) ( static_cast<void>( sizeof( char[1 - 2*!( cond ) ] ) ) ) +#endif + +#if defined(_MSC_VER) && _MSC_VER >= 1900 // Visual Studio 2015 and newer, or Clang emulating a corresponding MSVC +# define gsl_EMPTY_BASES_ __declspec(empty_bases) +#else +# define gsl_EMPTY_BASES_ +#endif + +#if gsl_HAVE( TYPE_TRAITS ) + +#define gsl_DEFINE_ENUM_BITMASK_OPERATORS_( ENUM ) \ + gsl_MAYBE_UNUSED gsl_NODISCARD gsl_api inline gsl_constexpr ENUM \ + operator~( ENUM val ) gsl_noexcept \ + { \ + typedef typename ::gsl_lite::std11::underlying_type<ENUM>::type U; \ + return ENUM( ~U( val ) ); \ + } \ + gsl_MAYBE_UNUSED gsl_NODISCARD gsl_api inline gsl_constexpr ENUM \ + operator|( ENUM lhs, ENUM rhs ) gsl_noexcept \ + { \ + typedef typename ::gsl_lite::std11::underlying_type<ENUM>::type U; \ + return ENUM( U( lhs ) | U( rhs ) ); \ + } \ + gsl_MAYBE_UNUSED gsl_NODISCARD gsl_api inline gsl_constexpr ENUM \ + operator&( ENUM lhs, ENUM rhs ) gsl_noexcept \ + { \ + typedef typename ::gsl_lite::std11::underlying_type<ENUM>::type U; \ + return ENUM( U( lhs ) & U( rhs ) ); \ + } \ + gsl_MAYBE_UNUSED gsl_NODISCARD gsl_api inline gsl_constexpr ENUM \ + operator^( ENUM lhs, ENUM rhs ) gsl_noexcept \ + { \ + typedef typename ::gsl_lite::std11::underlying_type<ENUM>::type U; \ + return ENUM( U( lhs ) ^ U( rhs ) ); \ + } \ + gsl_MAYBE_UNUSED gsl_api inline gsl_constexpr14 ENUM & \ + operator|=( ENUM & lhs, ENUM rhs ) gsl_noexcept \ + { \ + return lhs = lhs | rhs; \ + } \ + gsl_MAYBE_UNUSED gsl_api inline gsl_constexpr14 ENUM & \ + operator&=( ENUM & lhs, ENUM rhs ) gsl_noexcept \ + { \ + return lhs = lhs & rhs; \ + } \ + gsl_MAYBE_UNUSED gsl_api inline gsl_constexpr14 ENUM & \ + operator^=( ENUM & lhs, ENUM rhs ) gsl_noexcept \ + { \ + return lhs = lhs ^ rhs; \ + } + +#if gsl_STDLIB_CPP20_OR_GREATER +# define gsl_DEFINE_ENUM_RELATIONAL_OPERATORS_( ENUM ) \ + [[maybe_unused, nodiscard]] gsl_api inline constexpr std::strong_ordering \ + operator<=>( ENUM lhs, ENUM rhs ) gsl_noexcept \ + { \ + using U = std::underlying_type_t<ENUM>; \ + return U( lhs ) <=> U( rhs ); \ + } +#else // ! gsl_STDLIB_CPP20_OR_GREATER +# define gsl_DEFINE_ENUM_RELATIONAL_OPERATORS_( ENUM ) \ + gsl_MAYBE_UNUSED gsl_NODISCARD gsl_api inline gsl_constexpr bool \ + operator<( ENUM lhs, ENUM rhs ) gsl_noexcept \ + { \ + typedef typename ::gsl_lite::std11::underlying_type<ENUM>::type U; \ + return U( lhs ) < U( rhs ); \ + } \ + gsl_MAYBE_UNUSED gsl_NODISCARD gsl_api inline gsl_constexpr bool \ + operator>( ENUM lhs, ENUM rhs ) gsl_noexcept \ + { \ + typedef typename ::gsl_lite::std11::underlying_type<ENUM>::type U; \ + return U( lhs ) > U( rhs ); \ + } \ + gsl_MAYBE_UNUSED gsl_NODISCARD gsl_api inline gsl_constexpr bool \ + operator<=( ENUM lhs, ENUM rhs ) gsl_noexcept \ + { \ + typedef typename ::gsl_lite::std11::underlying_type<ENUM>::type U; \ + return U( lhs ) <= U( rhs ); \ + } \ + gsl_MAYBE_UNUSED gsl_NODISCARD gsl_api inline gsl_constexpr bool \ + operator>=( ENUM lhs, ENUM rhs ) gsl_noexcept \ + { \ + typedef typename ::gsl_lite::std11::underlying_type<ENUM>::type U; \ + return U( lhs ) >= U( rhs ); \ + } +#endif // gsl_STDLIB_CPP20_OR_GREATER + + // + // Defines bitmask operators `|`, `&`, `^`, `~`, `|=`, `&=`, and `^=` for the given enum type. + // + // enum class Vegetables { tomato = 0b001, onion = 0b010, eggplant = 0b100 }; + // gsl_DEFINE_ENUM_BITMASK_OPERATORS( Vegetables ) + // +#define gsl_DEFINE_ENUM_BITMASK_OPERATORS( ENUM ) gsl_DEFINE_ENUM_BITMASK_OPERATORS_( ENUM ) + + // + // Defines relational operators `<=>`, `<`, `>`, `<=`, `>=` for the given enum type. + // + // enum class OperatorPrecedence { additive = 0, multiplicative = 1, power = 2 }; + // gsl_DEFINE_ENUM_RELATIONAL_OPERATORS( OperatorPrecedence ) + // +#define gsl_DEFINE_ENUM_RELATIONAL_OPERATORS( ENUM ) gsl_DEFINE_ENUM_RELATIONAL_OPERATORS_( ENUM ) + +#endif // gsl_HAVE( TYPE_TRAITS ) + +#define gsl_DIMENSION_OF( a ) ( sizeof(a) / sizeof(0[a]) ) + + +// Method enabling (C++98, VC120 (VS2013) cannot use __VA_ARGS__) + +#if gsl_HAVE( EXPRESSION_SFINAE ) +# define gsl_TRAILING_RETURN_TYPE_(T) auto +# define gsl_RETURN_DECLTYPE_(EXPR) -> decltype( EXPR ) +#else +# define gsl_TRAILING_RETURN_TYPE_(T) T +# define gsl_RETURN_DECLTYPE_(EXPR) +#endif + +// NOTE: When using SFINAE in gsl-lite, please note that overloads of function templates must always use SFINAE with non-type default arguments +// as explained in https://en.cppreference.com/w/cpp/types/enable_if#Notes. `gsl_ENABLE_IF_()` implements graceful fallback to default +// type arguments (for compilers that don't support non-type default arguments); please verify that this is appropriate in the given +// situation, and add additional checks if necessary. +// +// Also, please note that `gsl_ENABLE_IF_()` doesn't enforce the constraint at all if no compiler/library support is available (i.e. pre-C++11). + +#if gsl_HAVE( TYPE_TRAITS ) +# define gsl_ENABLE_IF_R_( VA, T ) typename std::enable_if< ( VA ), T >::type +#else // ! gsl_HAVE( TYPE_TRAITS ) +# define gsl_ENABLE_IF_R_( VA, T ) T +#endif // gsl_HAVE( TYPE_TRAITS ) + +#if gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) +# define gsl_ENABLE_IF_NTTP_(VA) , typename std::enable_if< ( VA ), int >::type = 0 +# if ! gsl_BETWEEN( gsl_COMPILER_MSVC_VERSION, 1, 140 ) // VS 2013 seems to have trouble with SFINAE for default non-type arguments +# define gsl_ENABLE_IF_(VA) , typename std::enable_if< ( VA ), int >::type = 0 +# else +# define gsl_ENABLE_IF_(VA) , typename = typename std::enable_if< ( VA ), ::gsl_lite::detail::enabler >::type +# endif +#else +# define gsl_ENABLE_IF_NTTP_(VA) +# define gsl_ENABLE_IF_(VA) +#endif + + +// Link-time ABI incompatibility detection (MSVC only): + +#if defined( _MSC_VER ) && _MSC_VER >= 1900 // VS 2015 and newer +# if gsl_CONFIG( NARROW_THROWS_ON_TRUNCATION ) +# define gsl_CONFIG_NARROW_THROWS_ON_TRUNCATION_VAL_ 1 +# else +# define gsl_CONFIG_NARROW_THROWS_ON_TRUNCATION_VAL_ 0 +# endif +# if defined( gsl_api ) +# define gsl_GSL_API_VAL_ gsl_api +# else +# define gsl_GSL_API_VAL_ default +# endif +//# pragma message( "v" gsl_STRINGIFY( gsl_lite_MAJOR ) " gsl_api:" gsl_STRINGIFY( gsl_GSL_API_VAL_ ) " gsl_CONFIG_SPAN_INDEX_TYPE:" gsl_STRINGIFY( gsl_CONFIG_SPAN_INDEX_TYPE ) " gsl_CONFIG_INDEX_TYPE:" gsl_STRINGIFY( gsl_CONFIG_INDEX_TYPE ) " gsl_CONFIG_NARROW_THROWS_ON_TRUNCATION:" gsl_STRINGIFY( gsl_CONFIG_NARROW_THROWS_ON_TRUNCATION_VAL_ ) ) +# pragma detect_mismatch( "gsl-lite", "v" gsl_STRINGIFY( gsl_lite_MAJOR ) " gsl_api:" gsl_STRINGIFY( gsl_GSL_API_VAL_ ) " gsl_CONFIG_SPAN_INDEX_TYPE:" gsl_STRINGIFY( gsl_CONFIG_SPAN_INDEX_TYPE ) " gsl_CONFIG_INDEX_TYPE:" gsl_STRINGIFY( gsl_CONFIG_INDEX_TYPE ) " gsl_CONFIG_NARROW_THROWS_ON_TRUNCATION:" gsl_STRINGIFY( gsl_CONFIG_NARROW_THROWS_ON_TRUNCATION_VAL_ ) ) +# undef gsl_CONFIG_NARROW_THROWS_ON_TRUNCATION_VAL_ +# undef gsl_GSL_API_VAL_ +#endif // defined( _MSC_VER ) && _MSC_VER >= 1900 + + +// Other features: + +#define gsl_HAVE_CONSTRAINED_SPAN_CONTAINER_CTOR ( gsl_HAVE_DEFAULT_FUNCTION_TEMPLATE_ARG && gsl_HAVE_CONTAINER_DATA_METHOD ) +#define gsl_HAVE_CONSTRAINED_SPAN_CONTAINER_CTOR_() gsl_HAVE_CONSTRAINED_SPAN_CONTAINER_CTOR + +#define gsl_HAVE_UNCONSTRAINED_SPAN_CONTAINER_CTOR ( gsl_CONFIG_ALLOWS_UNCONSTRAINED_SPAN_CONTAINER_CTOR && gsl_COMPILER_NVCC_VERSION == 0 ) +#define gsl_HAVE_UNCONSTRAINED_SPAN_CONTAINER_CTOR_() gsl_HAVE_UNCONSTRAINED_SPAN_CONTAINER_CTOR + +// GSL API (e.g. for CUDA platform): + +// Guidelines for using `gsl_api`: +// +// NVCC imposes the restriction that a function annotated `__host__ __device__` cannot call host-only or device-only functions. +// This makes `gsl_api` inappropriate for generic functions that call unknown code, e.g. the template constructors of `span<>` +// or functions like `finally()` which accept an arbitrary function object. +// It is often preferable to annotate functions only with `gsl_constexpr` or `gsl_constexpr14`. The "extended constexpr" mode +// of NVCC (currently an experimental feature) will implicitly consider constexpr functions `__host__ __device__` functions +// but tolerates calls to host-only or device-only functions. + +#if ! defined( gsl_api ) +# ifdef __CUDACC__ +# define gsl_api __host__ __device__ +# else +# define gsl_api /*gsl_api*/ +# endif +#endif + +// Additional includes: + +#if gsl_FEATURE( STRING_SPAN ) +# include <ios> // for ios_base, streamsize +# include <string> +#endif // gsl_FEATURE( STRING_SPAN ) + +#if ! gsl_CPP11_OR_GREATER +# include <algorithm> // for swap() before C++11 +#endif // ! gsl_CPP11_OR_GREATER + +#if gsl_HAVE( ARRAY ) +# include <array> // indirectly includes reverse_iterator<> +#endif + +#if ! gsl_HAVE( ARRAY ) +# include <iterator> // for reverse_iterator<> +#endif + +#if gsl_STDLIB_CPP20_OR_GREATER +# include <compare> +#endif // gsl_STDLIB_CPP20_OR_GREATER + +#if ! gsl_HAVE( CONSTRAINED_SPAN_CONTAINER_CTOR ) || ! gsl_HAVE( AUTO ) +# include <vector> +#endif + +#if gsl_HAVE( INITIALIZER_LIST ) +# include <initializer_list> +#endif + +#if defined( gsl_CONFIG_CONTRACT_VIOLATION_ASSERTS ) || gsl_DEVICE_CODE +# include <cassert> +#endif + +#if defined( gsl_CONFIG_CONTRACT_VIOLATION_TRAPS ) && gsl_COMPILER_MSVC_VERSION >= 110 // __fastfail() supported by VS 2012 and later +# include <intrin.h> +#endif + +#if gsl_HAVE( ENUM_CLASS ) && ( gsl_COMPILER_ARMCC_VERSION || gsl_COMPILER_NVHPC_VERSION ) && !defined( _WIN32 ) +# include <endian.h> +#endif + +#if gsl_HAVE( TYPE_TRAITS ) +# include <type_traits> // for enable_if<>, + // add_const<>, add_pointer<>, common_type<>, make_signed<>, remove_cv<>, remove_const<>, remove_volatile<>, remove_reference<>, remove_cvref<>, remove_pointer<>, underlying_type<>, + // is_assignable<>, is_constructible<>, is_const<>, is_convertible<>, is_integral<>, is_pointer<>, is_signed<>, + // integral_constant<>, declval() +#elif gsl_HAVE( TR1_TYPE_TRAITS ) +# include <tr1/type_traits> // for add_const<>, remove_cv<>, remove_const<>, remove_volatile<>, remove_reference<>, integral_constant<> +#endif + +// Declare __cxa_get_globals() or equivalent in namespace gsl_lite::detail for uncaught_exceptions(): + +#if ! gsl_HAVE( UNCAUGHT_EXCEPTIONS ) +# if defined( _MSC_VER ) // MS-STL with either MSVC or clang-cl +namespace gsl_lite { namespace detail { extern "C" char * __cdecl _getptd(); } } +# elif gsl_COMPILER_CLANG_VERSION || gsl_COMPILER_GNUC_VERSION || gsl_COMPILER_APPLECLANG_VERSION || gsl_COMPILER_NVHPC_VERSION +# if defined( __GLIBCXX__ ) || defined( __GLIBCPP__ ) // libstdc++: prototype from cxxabi.h +# include <cxxabi.h> +# elif ! defined( BOOST_CORE_UNCAUGHT_EXCEPTIONS_HPP_INCLUDED_ ) // libc++: prototype from Boost? +# if defined( __FreeBSD__ ) || defined( __OpenBSD__ ) +namespace __cxxabiv1 { struct __cxa_eh_globals; extern "C" __cxa_eh_globals * __cxa_get_globals(); } +# else +namespace __cxxabiv1 { struct __cxa_eh_globals; extern "C" __cxa_eh_globals * __cxa_get_globals() gsl_noexcept; } +# endif +# endif + namespace gsl_lite { namespace detail { using ::__cxxabiv1::__cxa_get_globals; } } +# endif +#endif // ! gsl_HAVE( UNCAUGHT_EXCEPTIONS ) + + +// Warning suppression macros: + +#if gsl_COMPILER_MSVC_VERSION >= 140 && ! gsl_COMPILER_NVCC_VERSION +# define gsl_SUPPRESS_MSGSL_WARNING(expr) [[gsl::suppress(expr)]] +# define gsl_SUPPRESS_MSVC_WARNING(code, descr) __pragma(warning(suppress: code) ) +# define gsl_DISABLE_MSVC_WARNINGS(codes) __pragma(warning(push)) __pragma(warning(disable: codes)) +# define gsl_RESTORE_MSVC_WARNINGS() __pragma(warning(pop )) +#else +// TODO: define for Clang +# define gsl_SUPPRESS_MSGSL_WARNING(expr) +# define gsl_SUPPRESS_MSVC_WARNING(code, descr) +# define gsl_DISABLE_MSVC_WARNINGS(codes) +# define gsl_RESTORE_MSVC_WARNINGS() +#endif + +// Warning suppressions: + +#if gsl_COMPILER_CLANG_VERSION || gsl_COMPILER_APPLECLANG_VERSION +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wweak-vtables" // because of `fail_fast` and `narrowing_error` +#endif // gsl_COMPILER_CLANG_VERSION || gsl_COMPILER_APPLECLANG_VERSION + +#if gsl_COMPILER_GNUC_VERSION +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wuseless-cast" // we use `static_cast<>()` in several places where it is possibly redundant depending on the configuration of the library +#endif // gsl_COMPILER_GNUC_VERSION + +// Suppress the following MSVC GSL warnings: +// - C26432: gsl::c.21 : if you define or delete any default operation in the type '...', define or delete them all +// - C26410: gsl::r.32 : the parameter 'ptr' is a reference to const unique pointer, use const T* or const T& instead +// - C26415: gsl::r.30 : smart pointer parameter 'ptr' is used only to access contained pointer. Use T* or T& instead +// - C26418: gsl::r.36 : shared pointer parameter 'ptr' is not copied or moved. Use T* or T& instead +// - C26472: gsl::t.1 : don't use a static_cast for arithmetic conversions; +// use brace initialization, gsl_lite::narrow_cast or gsl_lite::narrow +// - C26439: gsl::f.6 : special function 'function' can be declared 'noexcept' +// - C26440: gsl::f.6 : function 'function' can be declared 'noexcept' +// - C26455: gsl::f.6 : default constructor may not throw. Declare it 'noexcept' +// - C26473: gsl::t.1 : don't cast between pointer types where the source type and the target type are the same +// - C26481: gsl::b.1 : don't use pointer arithmetic. Use span instead +// - C26482: gsl::b.2 : only index into arrays using constant expressions +// - C26446: gsl::b.4 : prefer to use gsl_lite::at() instead of unchecked subscript operator +// - C26490: gsl::t.1 : don't use reinterpret_cast +// - C26487: gsl::l.4 : don't return a pointer '(<some number>'s result)' that may be invalid +// - C26434: gsl::c.128 : function 'symbol_1' hides a non-virtual function 'symbol_2' (false positive for compiler-generated functions such as constructors) +// - C26456: gsl::c.128 : operator 'symbol_1' hides a non-virtual operator 'symbol_2' (false positive for compiler-generated operators) +// - C26457: es.48 : (void) should not be used to ignore return values, use 'std::ignore =' instead + +gsl_DISABLE_MSVC_WARNINGS( 26432 26410 26415 26418 26472 26439 26440 26455 26473 26481 26482 26446 26490 26487 26434 26456 26457 ) +#if gsl_BETWEEN( gsl_COMPILER_MSVC_VERSION, 110, 140 ) // VS 2012 and 2013 +# pragma warning(disable: 4127) // conditional expression is constant +#endif // gsl_BETWEEN( gsl_COMPILER_MSVC_VERSION, 110, 140 ) +#if gsl_COMPILER_MSVC_VERSION == 140 // VS 2015 +# pragma warning(disable: 4577) // 'noexcept' used with no exception handling mode specified; termination on exception is not guaranteed. Specify /EHsc +#endif // gsl_COMPILER_MSVC_VERSION == 140 + +namespace gsl_lite { + +// forward declare span<>: + +#if gsl_CPP17_OR_GREATER +inline +#endif // gsl_CPP17_OR_GREATER +gsl_constexpr const gsl_CONFIG_SPAN_INDEX_TYPE dynamic_extent = static_cast<gsl_CONFIG_SPAN_INDEX_TYPE>( -1 ); + +template< class T, gsl_CONFIG_SPAN_INDEX_TYPE Extent = dynamic_extent > +class span; + +namespace detail { + +#if gsl_FEATURE( STRING_SPAN ) || gsl_CONFIG( ALLOWS_SPAN_COMPARISON ) +// We implement `equal()` and `lexicographical_compare()` here to avoid having to pull in the <algorithm> header. +template< class InputIt1, class InputIt2 > +bool equal( InputIt1 first1, InputIt1 last1, InputIt2 first2 ) +{ + // Implementation borrowed from https://en.cppreference.com/w/cpp/algorithm/equal. + for ( ; first1 != last1; ++first1, ++first2 ) + { + if ( ! (*first1 == *first2 ) ) return false; + } + return true; +} +template< class InputIt1, class InputIt2 > +bool lexicographical_compare( InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2 ) +{ + // Implementation borrowed from https://en.cppreference.com/w/cpp/algorithm/lexicographical_compare. + for ( ; first1 != last1 && first2 != last2; ++first1, static_cast< void >( ++first2 ) ) + { + if ( *first1 < *first2 ) return true; + if ( *first2 < *first1 ) return false; + } + return first1 == last1 && first2 != last2; +} +#endif // gsl_FEATURE( STRING_SPAN ) || gsl_CONFIG( ALLOWS_SPAN_COMPARISON ) + +} // namespace detail + +// C++11 emulation: + +namespace std11 { + +template< class T > struct add_const { typedef const T type; }; + +template< class T > struct remove_const { typedef T type; }; +template< class T > struct remove_const<T const> { typedef T type; }; + +template< class T > struct remove_volatile { typedef T type; }; +template< class T > struct remove_volatile<T volatile> { typedef T type; }; + +template< class T > +struct remove_cv +{ + typedef typename remove_volatile<typename remove_const<T>::type>::type type; +}; + +template< class T > struct remove_reference { typedef T type; }; +template< class T > struct remove_reference<T&> { typedef T type; }; +#if gsl_HAVE( RVALUE_REFERENCE ) +template< class T > struct remove_reference<T&&> { typedef T type; }; +#endif + +#if gsl_HAVE( ALIAS_TEMPLATE ) +template< class T > using add_const_t = typename add_const<T>::type; +template< class T > using remove_const_t = typename remove_const<T>::type; +template< class T > using remove_volatile_t = typename remove_volatile<T>::type; +template< class T > using remove_cv_t = typename remove_cv<T>::type; +template< class T > using remove_reference_t = typename remove_reference<T>::type; +#endif // gsl_HAVE( ALIAS_TEMPLATE ) + + +#if gsl_HAVE( INTEGRAL_CONSTANT ) + +using std::integral_constant; +using std::true_type; +using std::false_type; + +#elif gsl_HAVE( TR1_INTEGRAL_CONSTANT ) + +using std::tr1::integral_constant; +using std::tr1::true_type; +using std::tr1::false_type; + +#else + +template< class T, T v > struct integral_constant { enum { value = v }; }; +typedef integral_constant< bool, true > true_type; +typedef integral_constant< bool, false > false_type; + +#endif + +#if gsl_HAVE( TYPE_TRAITS ) + +using std::underlying_type; + +#elif gsl_HAVE( TR1_TYPE_TRAITS ) + +using std::tr1::underlying_type; + +#else + +// We could try to define `underlying_type<>` for pre-C++11 here, but let's not until someone actually needs it. + +#endif + +} // namespace std11 + +// C++14 emulation: + +namespace std14 { + +#if gsl_HAVE( UNIQUE_PTR ) +# if gsl_HAVE( MAKE_UNIQUE ) + +using std::make_unique; + +# elif gsl_HAVE( VARIADIC_TEMPLATE ) + +template< class T, class... Args > +gsl_NODISCARD std::unique_ptr<T> +make_unique( Args &&... args ) +{ +# if gsl_HAVE( TYPE_TRAITS ) + static_assert( !std::is_array<T>::value, "make_unique<T[]>() is not part of C++14" ); +# endif + return std::unique_ptr<T>( new T( std::forward<Args>( args )... ) ); +} + +# endif // gsl_HAVE( MAKE_UNIQUE ), gsl_HAVE( VARIADIC_TEMPLATE ) +#endif // gsl_HAVE( UNIQUE_PTR ) + +} // namespace std14 + +namespace detail { + +#if gsl_HAVE( VARIADIC_TEMPLATE ) + +template < bool V0, class T0, class... Ts > struct conjunction_ { using type = T0; }; +template < class T0, class T1, class... Ts > struct conjunction_<true, T0, T1, Ts...> : conjunction_<T1::value, T1, Ts...> { }; +template < bool V0, class T0, class... Ts > struct disjunction_ { using type = T0; }; +template < class T0, class T1, class... Ts > struct disjunction_<false, T0, T1, Ts...> : disjunction_<T1::value, T1, Ts...> { }; + +#else // a.k.a. ! gsl_HAVE( VARIADIC_TEMPLATE ) + +template < bool V0, class T0, class T1 > struct conjunction_ { typedef T0 type; }; +template < class T0, class T1 > struct conjunction_<true, T0, T1> { typedef T1 type; }; +template < bool V0, class T0, class T1 > struct disjunction_ { typedef T0 type; }; +template < class T0, class T1 > struct disjunction_<false, T0, T1> { typedef T1 type; }; + +#endif // gsl_HAVE( VARIADIC_TEMPLATE ) + + +template <typename> struct dependent_false : std11::integral_constant<bool, false> { }; + +} // namespace detail + +// C++17 emulation: + +namespace std17 { + +template< bool v > struct bool_constant : std11::integral_constant<bool, v>{}; + +template < class T > struct negation : std11::integral_constant<bool, !T::value> { }; + +#if gsl_CPP11_120 + +template < class... Ts > struct conjunction; +template < > struct conjunction< > : std11::true_type { }; +template < class T0, class... Ts > struct conjunction<T0, Ts...> : detail::conjunction_<T0::value, T0, Ts...>::type { }; +template < class... Ts > struct disjunction; +template < > struct disjunction< > : std11::false_type { }; +template < class T0, class... Ts > struct disjunction<T0, Ts...> : detail::disjunction_<T0::value, T0, Ts...>::type { }; + +# if gsl_CPP14_OR_GREATER + +template < class... Ts > constexpr bool conjunction_v = conjunction<Ts...>::value; +template < class... Ts > constexpr bool disjunction_v = disjunction<Ts...>::value; +template < class T > constexpr bool negation_v = negation<T>::value; + +# endif // gsl_CPP14_OR_GREATER + +template< class... Ts > +struct make_void { typedef void type; }; + +template< class... Ts > +using void_t = typename make_void< Ts... >::type; + +#else // a.k.a. ! gsl_CPP11_120 + +// For C++98, define simpler binary variants of `conjunction<>` and `disjunction<>`. +template < class T0, class T1 > struct conjunction : detail::conjunction_<T0::value, T0, T1>::type { }; +template < class T0, class T1 > struct disjunction : detail::disjunction_<T0::value, T0, T1>::type { }; + +#endif // gsl_CPP11_120 + +#if gsl_HAVE( CONSTRAINED_SPAN_CONTAINER_CTOR ) + +template< class T, size_t N > +gsl_NODISCARD gsl_api inline gsl_constexpr auto +size( T const(&)[N] ) gsl_noexcept -> size_t +{ + return N; +} + +template< class C > +gsl_NODISCARD inline gsl_constexpr auto +size( C const & cont ) -> decltype( cont.size() ) +{ + return cont.size(); +} + +template< class T, size_t N > +gsl_NODISCARD gsl_api inline gsl_constexpr auto +data( T(&arr)[N] ) gsl_noexcept -> T* +{ + return &arr[0]; +} + +template< class C > +gsl_NODISCARD inline gsl_constexpr auto +data( C & cont ) -> decltype( cont.data() ) +{ + return cont.data(); +} + +template< class C > +gsl_NODISCARD inline gsl_constexpr auto +data( C const & cont ) -> decltype( cont.data() ) +{ + return cont.data(); +} + +# if gsl_HAVE( INITIALIZER_LIST ) +template< class E > +gsl_NODISCARD inline gsl_constexpr E const * +data( std::initializer_list<E> il ) gsl_noexcept +{ + return il.begin(); +} +# endif // gsl_HAVE( INITIALIZER_LIST ) + +#endif // gsl_HAVE( CONSTRAINED_SPAN_CONTAINER_CTOR ) + +} // namespace std17 + +#if gsl_HAVE( CONSTRAINED_SPAN_CONTAINER_CTOR ) +using std17::data; +using std17::size; +#endif // gsl_HAVE( CONSTRAINED_SPAN_CONTAINER_CTOR ) + +// C++20 emulation: + +namespace std20 { + +#if gsl_CPP11_100 + +struct identity +{ + template < class T > + gsl_constexpr T && operator ()( T && arg ) const gsl_noexcept + { + return std::forward<T>( arg ); + } +}; + +# if gsl_HAVE( ENUM_CLASS ) +enum class endian +{ +# if defined( _WIN32 ) + little = 0, + big = 1, + native = little +# elif gsl_COMPILER_GNUC_VERSION || gsl_COMPILER_CLANG_VERSION || gsl_COMPILER_APPLECLANG_VERSION + little = __ORDER_LITTLE_ENDIAN__, + big = __ORDER_BIG_ENDIAN__, + native = __BYTE_ORDER__ +# elif gsl_COMPILER_ARMCC_VERSION || gsl_COMPILER_NVHPC_VERSION + // from <endian.h> header file + little = __LITTLE_ENDIAN, + big = __BIG_ENDIAN, + native = __BYTE_ORDER +# else +// Do not define any endianness constants for unknown compilers. +# endif +}; +# endif // gsl_HAVE( ENUM_CLASS ) + +#endif // gsl_CPP11_100 + +template< class T > +struct type_identity +{ + typedef T type; +}; +#if gsl_HAVE( ALIAS_TEMPLATE ) +template< class T > +using type_identity_t = typename type_identity<T>::type; +#endif // gsl_HAVE( ALIAS_TEMPLATE ) + +#if gsl_HAVE( STD_SSIZE ) + +using std::ssize; + +#elif gsl_HAVE( CONSTRAINED_SPAN_CONTAINER_CTOR ) + +template < class C > +gsl_NODISCARD gsl_constexpr auto +ssize( C const & c ) + -> typename std::common_type<std::ptrdiff_t, typename std::make_signed<decltype(c.size())>::type>::type +{ + using R = typename std::common_type<std::ptrdiff_t, typename std::make_signed<decltype(c.size())>::type>::type; + return static_cast<R>( c.size() ); +} + +template <class T, std::size_t N> +gsl_NODISCARD gsl_constexpr auto +ssize( T const(&)[N] ) gsl_noexcept -> std::ptrdiff_t +{ + return std::ptrdiff_t( N ); +} + +#endif // gsl_HAVE( STD_SSIZE ) + +template< class T > struct remove_cvref { typedef typename std11::remove_cv< typename std11::remove_reference< T >::type >::type type; }; +#if gsl_HAVE( ALIAS_TEMPLATE ) +template< class T > using remove_cvref_t = typename remove_cvref<T>::type; +#endif // gsl_HAVE( ALIAS_TEMPLATE ) + +} // namespace std20 + +#if gsl_HAVE( STD_SSIZE ) || gsl_HAVE( CONSTRAINED_SPAN_CONTAINER_CTOR ) +using std20::ssize; +#endif // gsl_HAVE( STD_SSIZE ) || gsl_HAVE( CONSTRAINED_SPAN_CONTAINER_CTOR ) + +#if gsl_CPP11_100 +using std20::identity; +#endif // gsl_CPP11_100 +using std20::type_identity; +#if gsl_HAVE( ALIAS_TEMPLATE ) +using std20::type_identity_t; +#endif // gsl_HAVE( ALIAS_TEMPLATE ) + +// C++23 emulation: + +namespace std23 { + +} // namespace std23 + +namespace detail { + +/// for gsl_ENABLE_IF_() + +/*enum*/ class enabler{}; + +#if gsl_HAVE( TYPE_TRAITS ) + +template< class Q > +struct is_span_oracle : std::false_type{}; + +template< class T, gsl_CONFIG_SPAN_INDEX_TYPE Extent > +struct is_span_oracle< span<T, Extent > > : std::true_type{}; + +template< class Q > +struct is_span : is_span_oracle< typename std::remove_cv<Q>::type >{}; + +template< class Q > +struct is_std_array_oracle : std::false_type{}; + +# if gsl_HAVE( ARRAY ) + +template< class T, std::size_t Extent > +struct is_std_array_oracle< std::array<T, Extent> > : std::true_type{}; + +# endif + +template< class Q > +struct is_std_array : is_std_array_oracle< typename std::remove_cv<Q>::type >{}; + +template< class Q > +struct is_array : std::false_type{}; + +template< class T > +struct is_array<T[]> : std::true_type{}; + +template< class T, std::size_t N > +struct is_array<T[N]> : std::true_type{}; + +# if gsl_CPP11_140 && ! gsl_BETWEEN( gsl_COMPILER_GNUC_VERSION, 1, 500 ) + +template< class, class = void > +struct has_size_and_data : std::false_type{}; + +template< class C > +struct has_size_and_data +< + C, std17::void_t< + decltype( std17::size(std::declval<C>()) ), + decltype( std17::data(std::declval<C>()) ) > +> : std::true_type{}; + +template< class, class, class = void > +struct is_compatible_element : std::false_type {}; + +template< class C, class E > +struct is_compatible_element +< + C, E, std17::void_t< + decltype( std17::data(std::declval<C>()) ), + typename std::remove_pointer<decltype( std17::data( std::declval<C&>() ) )>::type(*)[] > +> : std::is_convertible< typename std::remove_pointer<decltype( std17::data( std::declval<C&>() ) )>::type(*)[], E(*)[] >{}; + +template< class C > +struct is_container : std17::bool_constant +< + ! is_span< C >::value + && ! is_array< C >::value + && ! is_std_array< C >::value + && has_size_and_data< C >::value +>{}; + +template< class C, class E > +struct is_compatible_container : std17::bool_constant +< + is_container<C>::value + && is_compatible_element<C,E>::value +>{}; + +# else // ^^^ gsl_CPP11_140 && ! gsl_BETWEEN( gsl_COMPILER_GNUC_VERSION, 1, 500 ) ^^^ / vvv ! gsl_CPP11_140 || gsl_BETWEEN( gsl_COMPILER_GNUC_VERSION, 1, 500 ) vvv + +template< + class C, class E + , typename = typename std::enable_if< + ! is_span< C >::value + && ! is_array< C >::value + && ! is_std_array< C >::value + && ( std::is_convertible< typename std::remove_pointer<decltype( std17::data( std::declval<C&>() ) )>::type(*)[], E(*)[] >::value) + // && has_size_and_data< C >::value + , enabler>::type + , class = decltype( std17::size(std::declval<C>()) ) + , class = decltype( std17::data(std::declval<C>()) ) +> +# if gsl_BETWEEN( gsl_COMPILER_MSVC_VERSION, 1, 140 ) +// VS2013 has insufficient support for expression SFINAE; we cannot make `is_compatible_container<>` a proper type trait here +struct is_compatible_container : std::true_type { }; +# else +struct is_compatible_container_r { is_compatible_container_r(int); }; +template< class C, class E > +std::true_type is_compatible_container_f( is_compatible_container_r<C, E> ); +template< class C, class E > +std::false_type is_compatible_container_f( ... ); + +template< class C, class E > +struct is_compatible_container : decltype( is_compatible_container_f< C, E >( 0 ) ) { }; +# endif // gsl_BETWEEN( gsl_COMPILER_MSVC_VERSION, 1, 140 ) + +# endif // gsl_CPP11_140 && ! gsl_BETWEEN( gsl_COMPILER_GNUC_VERSION, 1, 500 ) + +#endif // gsl_HAVE( TYPE_TRAITS ) + +} // namespace detail + +// +// GSL.util: utilities +// + +// Integer type for indices (e.g. in a loop). +typedef gsl_CONFIG_INDEX_TYPE index; + +// Integer type for dimensions. +typedef gsl_CONFIG_INDEX_TYPE dim; + +// Integer type for array strides. +typedef gsl_CONFIG_INDEX_TYPE stride; + +// Integer type for pointer, iterator, or index differences. +typedef gsl_CONFIG_INDEX_TYPE diff; + +// +// GSL.owner: ownership pointers +// +#if gsl_HAVE( SHARED_PTR ) +using std::unique_ptr; +using std::shared_ptr; +#endif + +#if gsl_HAVE( ALIAS_TEMPLATE ) + template< class T +# if gsl_HAVE( TYPE_TRAITS ) + , typename = typename std::enable_if< std::is_pointer<T>::value >::type +# endif + > + using owner = T; +#endif + +#define gsl_HAVE_OWNER_TEMPLATE gsl_HAVE_ALIAS_TEMPLATE +#define gsl_HAVE_OWNER_TEMPLATE_() gsl_HAVE_OWNER_TEMPLATE + +// +// GSL.assert: assertions +// + +#define gsl_NO_OP_() ( static_cast<void>( 0 ) ) +#if gsl_HAVE( TYPE_TRAITS ) && gsl_CONFIG( VALIDATES_UNENFORCED_CONTRACT_EXPRESSIONS ) +# define gsl_ELIDE_( x ) static_assert( ::std::is_constructible<bool, decltype( x )>::value, "argument of contract check must be convertible to bool" ) +#else +# define gsl_ELIDE_( x ) gsl_NO_OP_() +#endif + +#if gsl_COMPILER_NVHPC_VERSION +// Suppress "controlling expression is constant" warning when using `gsl_Expects()`, `gsl_Ensures()`, `gsl_Assert()`, etc. +# define gsl_SUPPRESS_NVHPC_CONTROLLING_EXPRESSION_IS_CONSTANT_ _Pragma("diag_suppress 236") +# define gsl_RESTORE_NVHPC_CONTROLLING_EXPRESSION_IS_CONSTANT_ _Pragma("diag_default 236") +#else +# define gsl_SUPPRESS_NVHPC_CONTROLLING_EXPRESSION_IS_CONSTANT_ +# define gsl_RESTORE_NVHPC_CONTROLLING_EXPRESSION_IS_CONSTANT_ +#endif + +#if gsl_DEVICE_CODE +# if defined( gsl_CONFIG_DEVICE_UNENFORCED_CONTRACTS_ASSUME ) +# if gsl_COMPILER_NVCC_VERSION >= 113 +# define gsl_ASSUME_( x ) ( __builtin_assume( !!( x ) ) ) +# define gsl_ASSUME_UNREACHABLE_() __builtin_unreachable() +# else // unknown device compiler +# error gsl_CONFIG_DEVICE_UNENFORCED_CONTRACTS_ASSUME: gsl-lite does not know how to generate UB optimization hints in device code for this compiler; use gsl_CONFIG_DEVICE_UNENFORCED_CONTRACTS_ELIDE instead +# endif +# define gsl_CONTRACT_UNENFORCED_( x ) gsl_ASSUME_( x ) +# else // defined( gsl_CONFIG_DEVICE_UNENFORCED_CONTRACTS_ELIDE ) [default] +# define gsl_CONTRACT_UNENFORCED_( x ) gsl_ELIDE_( x ) +# endif +#else // host code +# if defined( gsl_CONFIG_UNENFORCED_CONTRACTS_ASSUME ) +# if gsl_COMPILER_MSVC_VERSION >= 140 +# define gsl_ASSUME_( x ) __assume( x ) +# define gsl_ASSUME_UNREACHABLE_() __assume( 0 ) +# elif gsl_COMPILER_GNUC_VERSION +# define gsl_ASSUME_( x ) ( ( x ) ? static_cast<void>(0) : __builtin_unreachable() ) +# define gsl_ASSUME_UNREACHABLE_() __builtin_unreachable() +# elif defined(__has_builtin) +# if __has_builtin(__builtin_unreachable) +# define gsl_ASSUME_( x ) ( ( x ) ? static_cast<void>(0) : __builtin_unreachable() ) +# define gsl_ASSUME_UNREACHABLE_() __builtin_unreachable() +# else +# error gsl_CONFIG_UNENFORCED_CONTRACTS_ASSUME: gsl-lite does not know how to generate UB optimization hints for this compiler; use gsl_CONFIG_UNENFORCED_CONTRACTS_ELIDE instead +# endif +# else +# error gsl_CONFIG_UNENFORCED_CONTRACTS_ASSUME: gsl-lite does not know how to generate UB optimization hints for this compiler; use gsl_CONFIG_UNENFORCED_CONTRACTS_ELIDE instead +# endif +# define gsl_CONTRACT_UNENFORCED_( x ) gsl_ASSUME_( x ) +# else // defined( gsl_CONFIG_UNENFORCED_CONTRACTS_ELIDE ) [default] +# define gsl_CONTRACT_UNENFORCED_( x ) gsl_ELIDE_( x ) +# endif +#endif // gsl_DEVICE_CODE + +#if gsl_DEVICE_CODE +# if gsl_COMPILER_NVCC_VERSION +# define gsl_TRAP_() __trap() +# elif defined(__has_builtin) +# if __has_builtin(__builtin_trap) +# define gsl_TRAP_() __builtin_trap() +# else +# error gsl-lite does not know how to generate a trap instruction for this device compiler +# endif +# else +# error gsl-lite does not know how to generate a trap instruction for this device compiler +# endif +# if defined( gsl_CONFIG_DEVICE_CONTRACT_VIOLATION_TRAPS ) +# define gsl_CONTRACT_CHECK_( str, x ) ( gsl_SUPPRESS_NVHPC_CONTROLLING_EXPRESSION_IS_CONSTANT_ ( x ) ? static_cast<void>(0) : gsl_TRAP_() gsl_RESTORE_NVHPC_CONTROLLING_EXPRESSION_IS_CONSTANT_ ) +# define gsl_FAILFAST_() ( gsl_TRAP_() ) +# elif defined( gsl_CONFIG_DEVICE_CONTRACT_VIOLATION_CALLS_HANDLER ) +# define gsl_CONTRACT_CHECK_( str, x ) ( gsl_SUPPRESS_NVHPC_CONTROLLING_EXPRESSION_IS_CONSTANT_ ( x ) ? static_cast<void>(0) : ::gsl_lite::fail_fast_assert_handler( #x, str, __FILE__, __LINE__ ) gsl_RESTORE_NVHPC_CONTROLLING_EXPRESSION_IS_CONSTANT_ ) +# define gsl_FAILFAST_() ( ::gsl_lite::fail_fast_assert_handler( "", "gsl-lite: failure", __FILE__, __LINE__ ), gsl_TRAP_() ) /* do not let the custom assertion handler continue execution */ +# else // defined( gsl_CONFIG_DEVICE_CONTRACT_VIOLATION_ASSERTS ) [default] +# if ! defined( NDEBUG ) +# define gsl_CONTRACT_CHECK_( str, x ) assert( str && ( x ) ) +# else +# define gsl_CONTRACT_CHECK_( str, x ) ( ( x ) ? static_cast<void>(0) : gsl_TRAP_() ) +# endif +# define gsl_FAILFAST_() ( gsl_TRAP_() ) +# endif +#else // host code +# if defined( gsl_CONFIG_CONTRACT_VIOLATION_TRAPS ) +# if gsl_COMPILER_MSVC_VERSION >= 110 // __fastfail() supported by VS 2012 and later +# define gsl_TRAP_() __fastfail( 0 ) /* legacy failure code for buffer-overrun errors, cf. winnt.h, "Fast fail failure codes" */ +# elif gsl_COMPILER_GNUC_VERSION +# define gsl_TRAP_() __builtin_trap() +# elif defined(__has_builtin) +# if __has_builtin(__builtin_trap) +# define gsl_TRAP_() __builtin_trap() +# else +# error gsl_CONFIG_CONTRACT_VIOLATION_TRAPS: gsl-lite does not know how to generate a trap instruction for this compiler; use gsl_CONFIG_CONTRACT_VIOLATION_TERMINATES instead +# endif +# else +# error gsl_CONFIG_CONTRACT_VIOLATION_TRAPS: gsl-lite does not know how to generate a trap instruction for this compiler; use gsl_CONFIG_CONTRACT_VIOLATION_TERMINATES instead +# endif +# define gsl_CONTRACT_CHECK_( str, x ) ( gsl_SUPPRESS_NVHPC_CONTROLLING_EXPRESSION_IS_CONSTANT_ ( x ) ? static_cast<void>(0) : gsl_TRAP_() gsl_RESTORE_NVHPC_CONTROLLING_EXPRESSION_IS_CONSTANT_ ) +# if gsl_COMPILER_MSVC_VERSION +# define gsl_FAILFAST_() ( gsl_TRAP_(), ::gsl_lite::detail::fail_fast_terminate() ) +# else +# define gsl_FAILFAST_() ( gsl_TRAP_() ) +# endif +# elif defined( gsl_CONFIG_CONTRACT_VIOLATION_CALLS_HANDLER ) +# define gsl_CONTRACT_CHECK_( str, x ) ( gsl_SUPPRESS_NVHPC_CONTROLLING_EXPRESSION_IS_CONSTANT_ ( x ) ? static_cast<void>(0) : ::gsl_lite::fail_fast_assert_handler( #x, str, __FILE__, __LINE__ ) gsl_RESTORE_NVHPC_CONTROLLING_EXPRESSION_IS_CONSTANT_ ) +# define gsl_FAILFAST_() ( ::gsl_lite::fail_fast_assert_handler( "", "gsl-lite: failure", __FILE__, __LINE__ ), ::gsl_lite::detail::fail_fast_terminate() ) /* do not let the custom assertion handler continue execution */ +# elif defined( gsl_CONFIG_CONTRACT_VIOLATION_ASSERTS ) +# if ! defined( NDEBUG ) +# define gsl_CONTRACT_CHECK_( str, x ) ( gsl_SUPPRESS_NVHPC_CONTROLLING_EXPRESSION_IS_CONSTANT_ assert( str && ( x ) ) gsl_RESTORE_NVHPC_CONTROLLING_EXPRESSION_IS_CONSTANT_ ) +# define gsl_FAILFAST_() ( gsl_SUPPRESS_NVHPC_CONTROLLING_EXPRESSION_IS_CONSTANT_ assert( ! "gsl-lite: failure" ) gsl_RESTORE_NVHPC_CONTROLLING_EXPRESSION_IS_CONSTANT_, ::gsl_lite::detail::fail_fast_abort() ) +# else +# define gsl_CONTRACT_CHECK_( str, x ) ( gsl_SUPPRESS_NVHPC_CONTROLLING_EXPRESSION_IS_CONSTANT_ ( x ) ? static_cast<void>(0) : ::gsl_lite::detail::fail_fast_abort() gsl_RESTORE_NVHPC_CONTROLLING_EXPRESSION_IS_CONSTANT_ ) +# define gsl_FAILFAST_() ( ::gsl_lite::detail::fail_fast_abort() ) +# endif +# elif defined( gsl_CONFIG_CONTRACT_VIOLATION_THROWS ) +# define gsl_CONTRACT_CHECK_( str, x ) ( gsl_SUPPRESS_NVHPC_CONTROLLING_EXPRESSION_IS_CONSTANT_ ( ( x ) ? static_cast<void>(0) : ::gsl_lite::detail::fail_fast_throw( str ": '" #x "' at " __FILE__ ":" gsl_STRINGIFY(__LINE__) ) ) gsl_RESTORE_NVHPC_CONTROLLING_EXPRESSION_IS_CONSTANT_ ) +# define gsl_FAILFAST_() ( ::gsl_lite::detail::fail_fast_throw( "gsl-lite: failure at " __FILE__ ":" gsl_STRINGIFY(__LINE__) ) ) +# else // defined( gsl_CONFIG_CONTRACT_VIOLATION_TERMINATES ) [default] +# define gsl_CONTRACT_CHECK_( str, x ) ( gsl_SUPPRESS_NVHPC_CONTROLLING_EXPRESSION_IS_CONSTANT_ ( ( x ) ? static_cast<void>(0) : ::gsl_lite::detail::fail_fast_terminate() ) gsl_RESTORE_NVHPC_CONTROLLING_EXPRESSION_IS_CONSTANT_ ) +# define gsl_FAILFAST_() ( ::gsl_lite::detail::fail_fast_terminate() ) +# endif +#endif // gsl_DEVICE_CODE + +#if ( !gsl_DEVICE_CODE && defined( gsl_CONFIG_CONTRACT_CHECKING_OFF ) ) || ( gsl_DEVICE_CODE && defined( gsl_CONFIG_DEVICE_CONTRACT_CHECKING_OFF ) ) +# define gsl_CHECK_CONTRACTS_ 0 +# define gsl_CHECK_DEBUG_CONTRACTS_ 0 +# define gsl_CHECK_AUDIT_CONTRACTS_ 0 +#elif ( !gsl_DEVICE_CODE && defined( gsl_CONFIG_CONTRACT_CHECKING_AUDIT ) ) || ( gsl_DEVICE_CODE && defined( gsl_CONFIG_DEVICE_CONTRACT_CHECKING_AUDIT ) ) +# define gsl_CHECK_CONTRACTS_ 1 +# define gsl_CHECK_DEBUG_CONTRACTS_ 1 +# define gsl_CHECK_AUDIT_CONTRACTS_ 1 +#else // gsl_CONFIG_[DEVICE_]CONTRACT_CHECKING_ON [default] +# define gsl_CHECK_CONTRACTS_ 1 +# if !defined( NDEBUG ) +# define gsl_CHECK_DEBUG_CONTRACTS_ 1 +# else // defined( NDEBUG ) +# define gsl_CHECK_DEBUG_CONTRACTS_ 0 +# endif +# define gsl_CHECK_AUDIT_CONTRACTS_ 0 +#endif + +#if gsl_CHECK_CONTRACTS_ && !defined( gsl_CONFIG_CONTRACT_CHECKING_EXPECTS_OFF ) +# define gsl_Expects( x ) gsl_CONTRACT_CHECK_( "gsl-lite: Precondition failure", x ) +#else +# define gsl_Expects( x ) gsl_CONTRACT_UNENFORCED_( x ) +#endif +#if gsl_CHECK_DEBUG_CONTRACTS_ && !defined( gsl_CONFIG_CONTRACT_CHECKING_EXPECTS_OFF ) +# define gsl_ExpectsDebug( x ) gsl_CONTRACT_CHECK_( "gsl-lite: Precondition failure (debug)", x ) +#else +# define gsl_ExpectsDebug( x ) gsl_ELIDE_( x ) +#endif +#if gsl_CHECK_AUDIT_CONTRACTS_ && !defined( gsl_CONFIG_CONTRACT_CHECKING_EXPECTS_OFF ) +# define gsl_ExpectsAudit( x ) gsl_CONTRACT_CHECK_( "gsl-lite: Precondition failure (audit)", x ) +#else +# define gsl_ExpectsAudit( x ) gsl_ELIDE_( x ) +#endif + +#if gsl_CHECK_CONTRACTS_ && !defined( gsl_CONFIG_CONTRACT_CHECKING_ENSURES_OFF ) +# define gsl_Ensures( x ) gsl_CONTRACT_CHECK_( "gsl-lite: Postcondition failure", x ) +#else +# define gsl_Ensures( x ) gsl_CONTRACT_UNENFORCED_( x ) +#endif +#if gsl_CHECK_DEBUG_CONTRACTS_ && !defined( gsl_CONFIG_CONTRACT_CHECKING_ENSURES_OFF ) +# define gsl_EnsuresDebug( x ) gsl_CONTRACT_CHECK_( "gsl-lite: Postcondition failure (debug)", x ) +#else +# define gsl_EnsuresDebug( x ) gsl_ELIDE_( x ) +#endif +#if gsl_CHECK_AUDIT_CONTRACTS_ && !defined( gsl_CONFIG_CONTRACT_CHECKING_ENSURES_OFF ) +# define gsl_EnsuresAudit( x ) gsl_CONTRACT_CHECK_( "gsl-lite: Postcondition failure (audit)", x ) +#else +# define gsl_EnsuresAudit( x ) gsl_ELIDE_( x ) +#endif + +#if gsl_CHECK_CONTRACTS_ && !defined( gsl_CONFIG_CONTRACT_CHECKING_ASSERT_OFF ) +# define gsl_Assert( x ) gsl_CONTRACT_CHECK_( "gsl-lite: Assertion failure", x ) +#else +# define gsl_Assert( x ) gsl_CONTRACT_UNENFORCED_( x ) +#endif +#if gsl_CHECK_DEBUG_CONTRACTS_ && !defined( gsl_CONFIG_CONTRACT_CHECKING_ASSERT_OFF ) +# define gsl_AssertDebug( x ) gsl_CONTRACT_CHECK_( "gsl-lite: Assertion failure (debug)", x ) +#else +# define gsl_AssertDebug( x ) gsl_ELIDE_( x ) +#endif +#if gsl_CHECK_AUDIT_CONTRACTS_ && !defined( gsl_CONFIG_CONTRACT_CHECKING_ASSERT_OFF ) +# define gsl_AssertAudit( x ) gsl_CONTRACT_CHECK_( "gsl-lite: Assertion failure (audit)", x ) +#else +# define gsl_AssertAudit( x ) gsl_ELIDE_( x ) +#endif + +#define gsl_FailFast() gsl_FAILFAST_() + +#undef gsl_CHECK_CONTRACTS_ +#undef gsl_CHECK_DEBUG_CONTRACTS_ +#undef gsl_CHECK_AUDIT_CONTRACTS_ + + +struct fail_fast : public std::logic_error +{ + explicit fail_fast( char const * message ) + : std::logic_error( message ) {} +}; + +namespace detail { + + +#if gsl_HAVE( EXCEPTIONS ) +gsl_NORETURN inline void fail_fast_throw( char const * message ) +{ + throw fail_fast( message ); +} +#endif // gsl_HAVE( EXCEPTIONS ) +gsl_NORETURN inline void fail_fast_terminate() gsl_noexcept +{ + std::terminate(); +} +gsl_NORETURN inline void fail_fast_abort() gsl_noexcept +{ + std::abort(); +} + +} // namespace detail + +// Should be defined by user +gsl_api void fail_fast_assert_handler( char const * expression, char const * message, char const * file, int line ); + +// +// GSL.util: utilities +// + +// Add uncaught_exceptions() for pre-2017 MSVC, GCC and Clang + +namespace std17 { + +#if gsl_HAVE( UNCAUGHT_EXCEPTIONS ) + +inline int uncaught_exceptions() gsl_noexcept +{ + return std::uncaught_exceptions(); +} + +#else // ! gsl_HAVE( UNCAUGHT_EXCEPTIONS ) +# if defined( _MSC_VER ) // MS-STL with either MSVC or clang-cl + +inline int uncaught_exceptions() gsl_noexcept +{ + return static_cast<int>( *reinterpret_cast<unsigned const*>( detail::_getptd() + (sizeof(void *) == 8 ? 0x100 : 0x90 ) ) ); +} + +# elif gsl_COMPILER_CLANG_VERSION || gsl_COMPILER_GNUC_VERSION || gsl_COMPILER_APPLECLANG_VERSION || gsl_COMPILER_NVHPC_VERSION + +inline int uncaught_exceptions() gsl_noexcept +{ + return ( static_cast<int>( *reinterpret_cast<unsigned const *>( reinterpret_cast<unsigned char const *>(detail::__cxa_get_globals()) + sizeof(void *) ) ) ); +} + +# endif +#endif + +} // namespace std17 + +namespace std11 { + +#if gsl_HAVE( UNCAUGHT_EXCEPTIONS ) || defined( _MSC_VER ) || gsl_COMPILER_CLANG_VERSION || gsl_COMPILER_GNUC_VERSION || gsl_COMPILER_APPLECLANG_VERSION || gsl_COMPILER_NVHPC_VERSION +// Retain alias for backward compatibility +using ::gsl_lite::std17::uncaught_exceptions; +#endif + +} // namespace std11 + +#if gsl_STDLIB_CPP11_110 + +gsl_DISABLE_MSVC_WARNINGS( 4702 ) // unreachable code + +template< class F > +class final_action +# if gsl_HAVE( OVERRIDE_FINAL ) +final +# endif +{ +public: + explicit final_action( F action ) gsl_noexcept + : action_( std::move( action ) ), invoke_( true ) + { + } + + // We only provide the move constructor for legacy defaults, or if we cannot rely on C++17 guaranteed copy elision. +# if ! gsl_CPP17_OR_GREATER + final_action( final_action && other ) gsl_noexcept + : action_( std::move( other.action_ ) ) + , invoke_( other.invoke_ ) + { + other.invoke_ = false; + } +# endif // ! gsl_CPP17_OR_GREATER + + gsl_SUPPRESS_MSGSL_WARNING(f.6) + ~final_action() gsl_noexcept + { + // Let the optimizer figure out that this check is redundant. + if ( invoke_ ) + { + action_(); + } + } + +gsl_is_delete_access: + final_action( final_action const & ) gsl_is_delete; + final_action & operator=( final_action const & ) gsl_is_delete; + final_action & operator=( final_action && ) gsl_is_delete; + +private: + F action_; + gsl_MAYBE_UNUSED_MEMBER bool invoke_; // member is defined unconditionally so as not to have ABI depend on C++ language support +}; + +template< class F > +gsl_NODISCARD inline final_action<typename std::decay<F>::type> +finally( F && action ) gsl_noexcept +{ + return final_action<typename std::decay<F>::type>( std::forward<F>( action ) ); +} + +# if gsl_FEATURE( EXPERIMENTAL_RETURN_GUARD ) + +template< class F > +class final_action_return +# if gsl_HAVE( OVERRIDE_FINAL ) +final +# endif +{ +public: + explicit final_action_return( F action ) gsl_noexcept + : action_( std::move( action ) ) + , exception_count_( std17::uncaught_exceptions() ) + { + } + + // We only provide the move constructor if we cannot rely on C++17 guaranteed copy elision. +# if ! gsl_CPP17_OR_GREATER + final_action_return( final_action_return && other ) gsl_noexcept + : action_( std::move( other.action_ ) ) + , exception_count_( other.exception_count_ ) + { + other.exception_count_ = -1; // abuse member as special "no-invoke" marker + } +# endif // ! gsl_CPP17_OR_GREATER + + gsl_SUPPRESS_MSGSL_WARNING(f.6) + ~final_action_return() gsl_noexcept + { + if ( std17::uncaught_exceptions() == exception_count_ ) // always false if `exception_count_ == -1` + { + action_(); + } + } + +gsl_is_delete_access: + final_action_return( final_action_return const & ) gsl_is_delete; + final_action_return & operator=( final_action_return const & ) gsl_is_delete; + final_action_return & operator=( final_action_return && ) gsl_is_delete; + +private: + F action_; + int exception_count_; +}; +template< class F > +class final_action_error +# if gsl_HAVE( OVERRIDE_FINAL ) +final +# endif +{ +public: + explicit final_action_error( F action ) gsl_noexcept + : action_( std::move( action ) ) + , exception_count_( std17::uncaught_exceptions() ) + { + } + + // We only provide the move constructor if we cannot rely on C++17 guaranteed copy elision. +# if ! gsl_CPP17_OR_GREATER + final_action_error( final_action_error && other ) gsl_noexcept + : action_( std::move( other.action_ ) ) + , exception_count_( other.exception_count_ ) + { + other.exception_count_ = -1; // abuse member as special "no-invoke" marker + } +# endif // ! gsl_CPP17_OR_GREATER + + gsl_SUPPRESS_MSGSL_WARNING(f.6) + ~final_action_error() gsl_noexcept + { + if ( exception_count_ != -1 ) // abuse member as special "no-invoke" marker + { + if ( std17::uncaught_exceptions() != exception_count_ ) + { + action_(); + } + } + } + +gsl_is_delete_access: + final_action_error( final_action_error const & ) gsl_is_delete; + final_action_error & operator=( final_action_error const & ) gsl_is_delete; + final_action_error & operator=( final_action_error && ) gsl_is_delete; + +private: + F action_; + int exception_count_; +}; + +template< class F > +gsl_NODISCARD inline final_action_return<typename std::decay<F>::type> +on_return( F && action ) gsl_noexcept +{ + return final_action_return<typename std::decay<F>::type>( std::forward<F>( action ) ); +} + +template< class F > +gsl_NODISCARD inline final_action_error<typename std::decay<F>::type> +on_error( F && action ) gsl_noexcept +{ + return final_action_error<typename std::decay<F>::type>( std::forward<F>( action ) ); +} + +# endif // gsl_FEATURE( EXPERIMENTAL_RETURN_GUARD ) + +gsl_RESTORE_MSVC_WARNINGS() + +#endif // gsl_STDLIB_CPP11_110 + +#if gsl_STDLIB_CPP11_120 + +template< class T, class U > +gsl_NODISCARD gsl_api inline gsl_constexpr T +narrow_cast( U && u ) gsl_noexcept +{ + return static_cast<T>( std::forward<U>( u ) ); +} + +#else // ! gsl_STDLIB_CPP11_120 + +template< class T, class U > +gsl_api inline T +narrow_cast( U u ) gsl_noexcept +{ + return static_cast<T>( u ); +} + +#endif // gsl_STDLIB_CPP11_120 + +struct narrowing_error : public std::exception +{ + char const * what() const gsl_noexcept +#if gsl_HAVE( OVERRIDE_FINAL ) + override +#endif + { + return "narrowing_error"; + } +}; + +#if gsl_HAVE( TYPE_TRAITS ) + +namespace detail { + + template< class T, class U > + struct is_same_signedness : public std::integral_constant<bool, std::is_signed<T>::value == std::is_signed<U>::value> {}; + +# if gsl_COMPILER_NVCC_VERSION || gsl_COMPILER_NVHPC_VERSION + // We do this to circumvent NVCC warnings about pointless unsigned comparisons with 0. + template< class T > + gsl_constexpr gsl_api bool is_negative( T value, std::true_type /*isSigned*/ ) gsl_noexcept + { + return value < T(); + } + template< class T > + gsl_constexpr gsl_api bool is_negative( T /*value*/, std::false_type /*isUnsigned*/ ) gsl_noexcept + { + return false; + } + template< class T, class U > + gsl_constexpr gsl_api bool have_same_sign( T, U, std::true_type /*isSameSignedness*/ ) gsl_noexcept + { + return true; + } + template< class T, class U > + gsl_constexpr gsl_api bool have_same_sign( T t, U u, std::false_type /*isSameSignedness*/ ) gsl_noexcept + { + return detail::is_negative( t, std::is_signed<T>() ) == detail::is_negative( u, std::is_signed<U>() ); + } +# endif // gsl_COMPILER_NVCC_VERSION || gsl_COMPILER_NVHPC_VERSION + +} // namespace detail + +#endif + +template< class T, class U > +gsl_NODISCARD gsl_constexpr14 +#if ! gsl_CONFIG( NARROW_THROWS_ON_TRUNCATION ) +gsl_api +#endif // ! gsl_CONFIG( NARROW_THROWS_ON_TRUNCATION ) +inline +gsl_ENABLE_IF_R_( std::is_arithmetic<T>::value, T ) +narrow( U u ) +{ +#if ! gsl_HAVE( EXCEPTIONS ) && gsl_CONFIG( NARROW_THROWS_ON_TRUNCATION ) + gsl_STATIC_ASSERT_( detail::dependent_false< T >::value, + "According to the GSL specification, narrow<>() throws an exception of type narrowing_error on truncation. Therefore " + "it cannot be used if exceptions are disabled. Consider using narrow_failfast<>() instead which raises a precondition " + "violation if the given value cannot be represented in the target type." ); +#endif + + T t = static_cast<T>( u ); + +#if gsl_HAVE( TYPE_TRAITS ) +# if gsl_COMPILER_NVCC_VERSION || gsl_COMPILER_NVHPC_VERSION + if ( static_cast<U>( t ) != u + || ! detail::have_same_sign( t, u, detail::is_same_signedness<T, U>() ) ) +# else + gsl_SUPPRESS_MSVC_WARNING( 4127, "conditional expression is constant" ) + if ( static_cast<U>( t ) != u + || ( ! detail::is_same_signedness<T, U>::value && ( t < T() ) != ( u < U() ) ) ) +# endif +#else + // Don't assume T() works: + gsl_SUPPRESS_MSVC_WARNING( 4127, "conditional expression is constant" ) +# if gsl_COMPILER_NVHPC_VERSION + // Suppress: pointless comparison of unsigned integer with zero. +# pragma diag_suppress 186 +# endif + if ( static_cast<U>( t ) != u + || ( t < 0 ) != ( u < 0 ) ) +# if gsl_COMPILER_NVHPC_VERSION + // Restore: pointless comparison of unsigned integer with zero. +# pragma diag_default 186 +# endif + +#endif + { +#if gsl_CONFIG( NARROW_THROWS_ON_TRUNCATION ) + throw narrowing_error(); +#else // ! gsl_CONFIG( NARROW_THROWS_ON_TRUNCATION ) +# if gsl_DEVICE_CODE + gsl_TRAP_(); +# else // host code + std::terminate(); +# endif +#endif // gsl_CONFIG( NARROW_THROWS_ON_TRUNCATION ) + } + + return t; +} +#if gsl_HAVE( TYPE_TRAITS ) +template< class T, class U > +gsl_NODISCARD gsl_constexpr14 +# if ! gsl_CONFIG( NARROW_THROWS_ON_TRUNCATION ) +gsl_api +# endif // ! gsl_CONFIG( NARROW_THROWS_ON_TRUNCATION ) +inline +gsl_ENABLE_IF_R_( !std::is_arithmetic<T>::value, T ) +narrow( U u ) +{ +# if ! gsl_HAVE( EXCEPTIONS ) && gsl_CONFIG( NARROW_THROWS_ON_TRUNCATION ) + gsl_STATIC_ASSERT_( detail::dependent_false< T >::value, + "According to the GSL specification, narrow<>() throws an exception of type narrowing_error on truncation. Therefore " + "it cannot be used if exceptions are disabled. Consider using narrow_failfast<>() instead which raises a precondition " + "violation if the given value cannot be represented in the target type." ); +# endif + + T t = static_cast<T>( u ); + + if ( static_cast<U>( t ) != u ) + { +# if gsl_CONFIG( NARROW_THROWS_ON_TRUNCATION ) + throw narrowing_error(); +# else // ! gsl_CONFIG( NARROW_THROWS_ON_TRUNCATION ) +# if gsl_DEVICE_CODE + gsl_TRAP_(); +# else // host code + std::terminate(); +# endif +# endif // gsl_CONFIG( NARROW_THROWS_ON_TRUNCATION ) + } + + return t; +} +#endif // gsl_HAVE( TYPE_TRAITS ) + +template< class T, class U > +gsl_NODISCARD gsl_api gsl_constexpr14 inline +gsl_ENABLE_IF_R_( std::is_arithmetic<T>::value, T ) +narrow_failfast( U u ) +{ + T t = static_cast<T>( u ); + +#if gsl_HAVE( TYPE_TRAITS ) +# if gsl_COMPILER_NVCC_VERSION || gsl_COMPILER_NVHPC_VERSION + gsl_Assert( static_cast<U>( t ) == u + && ::gsl_lite::detail::have_same_sign( t, u, ::gsl_lite::detail::is_same_signedness<T, U>() ) ); +# else + gsl_SUPPRESS_MSVC_WARNING( 4127, "conditional expression is constant" ) + gsl_Assert( static_cast<U>( t ) == u + && ( ::gsl_lite::detail::is_same_signedness<T, U>::value || ( t < T() ) == ( u < U() ) ) ); +# endif +#else + // Don't assume T() works: + gsl_SUPPRESS_MSVC_WARNING( 4127, "conditional expression is constant" ) +# if gsl_COMPILER_NVHPC_VERSION + // Suppress: pointless comparison of unsigned integer with zero. +# pragma diag_suppress 186 +# endif + gsl_Assert( static_cast<U>( t ) == u + && ( t < 0 ) == ( u < 0 ) ); +# if gsl_COMPILER_NVHPC_VERSION + // Restore: pointless comparison of unsigned integer with zero. +# pragma diag_default 186 +# endif +#endif + + return t; +} +#if gsl_HAVE( TYPE_TRAITS ) +template< class T, class U > +gsl_NODISCARD gsl_api gsl_constexpr14 inline +gsl_ENABLE_IF_R_( !std::is_arithmetic<T>::value, T ) +narrow_failfast( U u ) +{ + T t = static_cast<T>( u ); + gsl_Assert( static_cast<U>( t ) == u ); + return t; +} +#endif // gsl_HAVE( TYPE_TRAITS ) + + +// +// at() - Bounds-checked way of accessing static arrays, std::array, std::vector. +// + +template< class T, size_t N > +gsl_NODISCARD gsl_api inline gsl_constexpr14 T & +at( T(&arr)[N], size_t pos ) +{ + gsl_Expects( pos < N ); + return arr[pos]; +} + +template< class Container > +gsl_NODISCARD gsl_api inline gsl_constexpr14 typename Container::value_type & +at( Container & cont, size_t pos ) +{ + gsl_Expects( pos < cont.size() ); + return cont[pos]; +} + +template< class Container > +gsl_NODISCARD gsl_api inline gsl_constexpr14 typename Container::value_type const & +at( Container const & cont, size_t pos ) +{ + gsl_Expects( pos < cont.size() ); + return cont[pos]; +} + +#if gsl_HAVE( INITIALIZER_LIST ) +template< class T > +gsl_NODISCARD gsl_api inline const gsl_constexpr14 T +at( std::initializer_list<T> cont, size_t pos ) +{ + gsl_Expects( pos < cont.size() ); + return *( cont.begin() + pos ); +} +#endif + +template< class T, gsl_CONFIG_SPAN_INDEX_TYPE Extent > +gsl_NODISCARD gsl_api inline gsl_constexpr14 T & +at( span<T, Extent> s, size_t pos ) +{ + return s[ pos ]; +} + +// +// GSL.views: views +// + +// +// not_null<> - Wrap any indirection and enforce non-null. +// + +template< class T > +class not_null; + +namespace detail { + +template< class T > struct is_void : std11::false_type { }; +template< > struct is_void< void > : std11::true_type { }; + +// helper class to figure out whether a pointer has an element type +#if gsl_STDLIB_CPP11_OR_GREATER && gsl_HAVE( EXPRESSION_SFINAE ) +// Avoid SFINAE for unary `operator*` (doesn't work for `std::unique_ptr<>` and the like) if an `element_type` member exists. +template< class T, class E = void > +struct has_element_type_ : std11::false_type { }; +template< class T > +struct has_element_type_< T, std17::void_t< decltype( *std::declval<T>() ) > > : std11::true_type { }; +template< class T, class E = void > +struct has_element_type : has_element_type_< T > { }; +template< class T > +struct has_element_type< T, std17::void_t< typename T::element_type > > : std11::true_type { }; +# else // a.k.a. ! ( gsl_STDLIB_CPP11_OR_GREATER && gsl_HAVE( EXPRESSION_SFINAE ) ) +// Without C++11 and expression SFINAE, just assume that non-pointer types (e.g. smart pointers) have an `element_type` member +template< class T, class E = void > +struct has_element_type : std11::true_type { }; +# endif // gsl_STDLIB_CPP11_OR_GREATER && gsl_HAVE( EXPRESSION_SFINAE ) + +// helper class to figure out the pointed-to type of a pointer +#if gsl_STDLIB_CPP11_OR_GREATER +template< class T, class E = void > +struct element_type_helper +{ + // For types without a member element_type (this could handle typed raw pointers but not `void*`) + typedef typename std::remove_reference< decltype( *std::declval<T>() ) >::type type; +}; +template< class T > +struct element_type_helper< T, std17::void_t< typename T::element_type > > +{ + // For types with a member element_type + typedef typename T::element_type type; +}; +#else // ! gsl_STDLIB_CPP11_OR_GREATER +// Pre-C++11, we cannot have `decltype`, so we cannot handle non-pointer types without a member `element_type` +template< class T, class E = void > +struct element_type_helper +{ + typedef typename T::element_type type; +}; +#endif // gsl_STDLIB_CPP11_OR_GREATER +template< class T > +struct element_type_helper< T * > +{ + typedef T type; +}; + +template< class T > +struct is_not_null_or_bool_oracle : std11::false_type { }; +template< class T > +struct is_not_null_or_bool_oracle< not_null<T> > : std11::true_type { }; +template<> +struct is_not_null_or_bool_oracle< bool > : std11::true_type { }; + + +template< class T, bool IsCopyable > +struct not_null_data; +#if gsl_HAVE( MOVE_FORWARD ) +template< class T > +struct not_null_data< T, false > +{ + T ptr_; + + gsl_api gsl_constexpr14 not_null_data( T && _ptr ) gsl_noexcept + : ptr_( std::move( _ptr ) ) + { + } + + gsl_api gsl_constexpr14 not_null_data( not_null_data && other ) + gsl_noexcept_not_testing // we want to be nothrow-movable despite the assertion + : ptr_( std::move( other.ptr_ ) ) + { + gsl_Assert( ptr_ != gsl_nullptr ); + } + gsl_api gsl_constexpr14 not_null_data & operator=( not_null_data && other ) + gsl_noexcept_not_testing // we want to be nothrow-movable despite the assertion + { + gsl_Assert( other.ptr_ != gsl_nullptr || &other == this ); + ptr_ = std::move( other.ptr_ ); + return *this; + } + +gsl_is_delete_access: + not_null_data( not_null_data const & ) gsl_is_delete; + not_null_data & operator=( not_null_data const & ) gsl_is_delete; +}; +#endif // gsl_HAVE( MOVE_FORWARD ) +template< class T > +struct not_null_data< T, true > +{ + T ptr_; + + gsl_api gsl_constexpr14 not_null_data( T const & _ptr ) gsl_noexcept + : ptr_( _ptr ) + { + } + +#if gsl_HAVE( MOVE_FORWARD ) + gsl_api gsl_constexpr14 not_null_data( T && _ptr ) gsl_noexcept + : ptr_( std::move( _ptr ) ) + { + } + + gsl_api gsl_constexpr14 not_null_data( not_null_data && other ) + gsl_noexcept_not_testing // we want to be nothrow-movable despite the assertion + : ptr_( std::move( other.ptr_ ) ) + { + gsl_Assert( ptr_ != gsl_nullptr ); + } + gsl_api gsl_constexpr14 not_null_data & operator=( not_null_data && other ) + gsl_noexcept_not_testing // we want to be nothrow-movable despite the assertion + { + gsl_Assert( other.ptr_ != gsl_nullptr || &other == this ); + ptr_ = std::move( other.ptr_ ); + return *this; + } +#endif // gsl_HAVE( MOVE_FORWARD ) + + gsl_api gsl_constexpr14 not_null_data( not_null_data const & other ) + : ptr_( other.ptr_ ) + { + gsl_Assert( ptr_ != gsl_nullptr ); + } + gsl_api gsl_constexpr14 not_null_data & operator=( not_null_data const & other ) + { + gsl_Assert( other.ptr_ != gsl_nullptr ); + ptr_ = other.ptr_; + return *this; + } +}; +template< class T > +struct not_null_data< T *, true > +{ + T * ptr_; + + gsl_api gsl_constexpr14 not_null_data( T * _ptr ) gsl_noexcept + : ptr_( _ptr ) + { + } +}; + +template< class T > +struct is_copyable +#if gsl_HAVE( TYPE_TRAITS ) +: std::integral_constant< bool, std::is_copy_constructible<T>::value && std::is_copy_assignable<T>::value > +#else +: std11::true_type +#endif +{ +}; +#if gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( UNIQUE_PTR ) && gsl_BETWEEN( gsl_COMPILER_MSVC_VERSION, 1, 140 ) +// Type traits are buggy in VC++ 2013, so we explicitly declare `unique_ptr<>` non-copyable. +template< class T, class Deleter > +struct is_copyable< std::unique_ptr< T, Deleter > > : std11::false_type +{ +}; +#endif + +template< class T > +struct not_null_accessor; + +template< class Derived, class T, bool HasElementType > +struct not_null_elem +{ + typedef typename element_type_helper<T>::type element_type; + +#if gsl_CONFIG( TRANSPARENT_NOT_NULL ) + gsl_NODISCARD gsl_api gsl_constexpr14 element_type * + get() const + { + return not_null_accessor<T>::get_checked( static_cast< Derived const & >( *this ) ).get(); + } +#endif // gsl_CONFIG( TRANSPARENT_NOT_NULL ) +}; +template< class Derived, class T > +struct not_null_elem< Derived, T, false > +{ +}; +template< class Derived, class T, bool IsDereferencable > +struct gsl_EMPTY_BASES_ not_null_deref + : not_null_elem< Derived, T, detail::has_element_type< T >::value > +{ + gsl_NODISCARD gsl_api gsl_constexpr14 typename element_type_helper<T>::type & + operator*() const + { + return *not_null_accessor<T>::get_checked( static_cast< Derived const & >( *this ) ); + } +}; +template< class Derived, class T > +struct gsl_EMPTY_BASES_ not_null_deref< Derived, T, false > // e.g. `void*`, `std::function<>` + : not_null_elem< Derived, T, detail::has_element_type< T >::value > +{ +}; + +template< class T > struct is_void_ptr : is_void< typename detail::element_type_helper< T >::type > { }; + +template< class T > struct is_dereferencable : std17::conjunction< has_element_type< T >, std17::negation< is_void_ptr< T > > > { }; + +} // namespace detail + +#if gsl_HAVE( TYPE_TRAITS ) +template< class T > struct is_nullable : std::is_assignable< typename std::remove_cv< T >::type &, std::nullptr_t > { }; + +# if gsl_CPP14_OR_GREATER +template< class T > constexpr bool is_nullable_v = is_nullable< T >::value; +# endif // gsl_CPP14_OR_GREATER + +#endif // gsl_HAVE( TYPE_TRAITS ) + +template< class T > +class +gsl_EMPTY_BASES_ // not strictly needed, but will become necessary if we add more base classes +not_null : public detail::not_null_deref< not_null< T >, T, detail::is_dereferencable< T >::value > +{ +private: + detail::not_null_data< T, detail::is_copyable< T >::value > data_; + + // need to access `not_null<U>::data_` + template< class U > + friend struct detail::not_null_accessor; + + typedef detail::not_null_accessor<T> accessor; + +public: +#if gsl_HAVE( TYPE_TRAITS ) + static_assert( ! std::is_reference<T>::value, "T may not be a reference type" ); + static_assert( ! std::is_const<T>::value && ! std::is_volatile<T>::value, "T may not be cv-qualified" ); + static_assert( is_nullable<T>::value, "T must be a nullable type" ); +#endif + +#if gsl_CONFIG( NOT_NULL_EXPLICIT_CTOR ) +# if gsl_HAVE( MOVE_FORWARD ) + template< class U + // In Clang 3.x, `is_constructible<not_null<unique_ptr<X>>, unique_ptr<X>>` tries to instantiate the copy constructor of `unique_ptr<>`, triggering an error. + // Note that Apple Clang's `__clang_major__` etc. are different from regular Clang. +# if gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) && ! gsl_BETWEEN( gsl_COMPILER_CLANG_VERSION, 1, 400 ) && ! gsl_BETWEEN( gsl_COMPILER_APPLECLANG_VERSION, 1, 1001 ) + // We *have* to use SFINAE with an NTTP arg here, otherwise the overload is ambiguous. + gsl_ENABLE_IF_NTTP_(( std::is_constructible<T, U>::value && is_nullable<U>::value )) +# endif + > + gsl_api gsl_constexpr14 explicit not_null( U other ) + : data_( T( std::move( other ) ) ) + { + gsl_Expects( data_.ptr_ != gsl_nullptr ); + } +# if gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) && ! gsl_BETWEEN( gsl_COMPILER_CLANG_VERSION, 1, 400 ) && ! gsl_BETWEEN( gsl_COMPILER_APPLECLANG_VERSION, 1, 1001 ) + // Define the non-explicit constructors for non-nullable arguments only if the explicit constructor has a SFINAE constraint. + template< class U + // We *have* to use SFINAE with an NTTP arg here, otherwise the overload is ambiguous. + gsl_ENABLE_IF_NTTP_(( std::is_constructible<T, U>::value && std::is_function<U>::value )) + > + gsl_api gsl_constexpr14 /*implicit*/ not_null( U const & other ) + : data_( T( other ) ) + { + } + template< class U + // We *have* to use SFINAE with an NTTP arg here, otherwise the overload is ambiguous. + gsl_ENABLE_IF_NTTP_(( std::is_constructible<T, U>::value && ! std::is_function<U>::value && ! is_nullable<U>::value )) + > + gsl_api gsl_constexpr14 /*implicit*/ not_null( U other ) + : data_( T( std::move( other ) ) ) + { + gsl_Expects( data_.ptr_ != gsl_nullptr ); + } +# endif // gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) && ! gsl_BETWEEN( gsl_COMPILER_CLANG_VERSION, 1, 400 ) && ! gsl_BETWEEN( gsl_COMPILER_APPLECLANG_VERSION, 1, 1001 ) +# else // a.k.a. ! gsl_HAVE( MOVE_FORWARD ) + template< class U > + gsl_api gsl_constexpr14 explicit not_null( U const & other ) + : data_( T( other ) ) + { + gsl_Expects( data_.ptr_ != gsl_nullptr ); + } +# endif // gsl_HAVE( MOVE_FORWARD ) +#else // a.k.a. !gsl_CONFIG( NOT_NULL_EXPLICIT_CTOR ) +# if gsl_HAVE( MOVE_FORWARD ) + // In Clang 3.x, `is_constructible<not_null<unique_ptr<X>>, unique_ptr<X>>` tries to instantiate the copy constructor of `unique_ptr<>`, triggering an error. + // Note that Apple Clang's `__clang_major__` etc. are different from regular Clang. +# if gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) && ! gsl_BETWEEN( gsl_COMPILER_CLANG_VERSION, 1, 400 ) && ! gsl_BETWEEN( gsl_COMPILER_APPLECLANG_VERSION, 1, 1001 ) + template< class U + // We *have* to use SFINAE with an NTTP arg here, otherwise the overload is ambiguous. + gsl_ENABLE_IF_NTTP_(( std::is_constructible<T, U>::value && !std::is_convertible<U, T>::value )) + > + gsl_api gsl_constexpr14 explicit not_null( U other ) + : data_( T( std::move( other ) ) ) + { + gsl_Expects( data_.ptr_ != gsl_nullptr ); + } + + template< class U + // We *have* to use SFINAE with an NTTP arg here, otherwise the overload is ambiguous. + gsl_ENABLE_IF_NTTP_(( std::is_convertible<U, T>::value )) + > + gsl_api gsl_constexpr14 not_null( U other ) + : data_( std::move( other ) ) + { + gsl_Expects( data_.ptr_ != gsl_nullptr ); + } +# else // a.k.a. !( gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) && ! gsl_BETWEEN( gsl_COMPILER_CLANG_VERSION, 1, 400 ) && ! gsl_BETWEEN( gsl_COMPILER_APPLECLANG_VERSION, 1, 1001 ) + // If type_traits are not available, then we can't distinguish `is_convertible<>` and `is_constructible<>`, so we unconditionally permit implicit construction. + template< class U > + gsl_api gsl_constexpr14 not_null( U other ) + : data_( T( std::move( other ) ) ) + { + gsl_Expects( data_.ptr_ != gsl_nullptr ); + } +# endif // gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) && ! gsl_BETWEEN( gsl_COMPILER_CLANG_VERSION, 1, 400 ) && ! gsl_BETWEEN( gsl_COMPILER_APPLECLANG_VERSION, 1, 1001 ) +# else // a.k.a. ! gsl_HAVE( MOVE_FORWARD ) + template< class U > + gsl_api gsl_constexpr14 not_null( U const & other ) + : data_( T( other ) ) + { + gsl_Expects( data_.ptr_ != gsl_nullptr ); + } +# endif // gsl_HAVE( MOVE_FORWARD ) +#endif // gsl_CONFIG( NOT_NULL_EXPLICIT_CTOR ) + +#if gsl_HAVE( MOVE_FORWARD ) + // In Clang 3.x, `is_constructible<not_null<unique_ptr<X>>, unique_ptr<X>>` tries to instantiate the copy constructor of `unique_ptr<>`, triggering an error. + // Note that Apple Clang's `__clang_major__` etc. are different from regular Clang. +# if gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) && ! gsl_BETWEEN( gsl_COMPILER_CLANG_VERSION, 1, 400 ) && ! gsl_BETWEEN( gsl_COMPILER_APPLECLANG_VERSION, 1, 1001 ) + template< class U + // We *have* to use SFINAE with an NTTP arg here, otherwise the overload is ambiguous. + gsl_ENABLE_IF_NTTP_(( std::is_constructible<T, U>::value && !std::is_convertible<U, T>::value )) + > + gsl_api gsl_constexpr14 explicit not_null( not_null<U> other ) + : data_( T( detail::not_null_accessor<U>::get_checked( std::move( other ) ) ) ) + { + } + + template< class U + // We *have* to use SFINAE with an NTTP arg here, otherwise the overload is ambiguous. + gsl_ENABLE_IF_NTTP_(( std::is_convertible<U, T>::value )) + > + gsl_api gsl_constexpr14 not_null( not_null<U> other ) + : data_( T( detail::not_null_accessor<U>::get_checked( std::move( other ) ) ) ) + { + } +# else // a.k.a. ! ( gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) && ! gsl_BETWEEN( gsl_COMPILER_CLANG_VERSION, 1, 400 ) && ! gsl_BETWEEN( gsl_COMPILER_APPLECLANG_VERSION, 1, 1001 ) + // If type_traits are not available, then we can't distinguish `is_convertible<>` and `is_constructible<>`, so we unconditionally permit implicit construction. + template< class U > + gsl_api gsl_constexpr14 not_null( not_null<U> other ) + : data_( T( detail::not_null_accessor<U>::get_checked( std::move( other ) ) ) ) + { + gsl_Expects( data_.ptr_ != gsl_nullptr ); + } + template< class U > + gsl_api gsl_constexpr14 not_null<T>& operator=( not_null<U> other ) + { + data_.ptr_ = detail::not_null_accessor<U>::get_checked( std::move( other ) ); + return *this; + } +# endif // gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) && ! gsl_BETWEEN( gsl_COMPILER_CLANG_VERSION, 1, 400 ) && ! gsl_BETWEEN( gsl_COMPILER_APPLECLANG_VERSION, 1, 1001 ) +#else // a.k.a. ! gsl_HAVE( MOVE_FORWARD ) + template< class U > + gsl_api gsl_constexpr14 not_null( not_null<U> const & other ) + : data_( T( detail::not_null_accessor<U>::get_checked( other ) ) ) + { + } + template< class U > + gsl_api gsl_constexpr14 not_null<T>& operator=( not_null<U> const & other ) + { + data_.ptr_ = detail::not_null_accessor<U>::get_checked( other ); + return *this; + } +#endif // gsl_HAVE( MOVE_FORWARD ) + +#if ! gsl_CONFIG( TRANSPARENT_NOT_NULL ) +# if gsl_CONFIG( NOT_NULL_GET_BY_CONST_REF ) + gsl_NODISCARD gsl_api gsl_constexpr14 T const & + get() const + { + return accessor::get_checked( *this ); + } +# else // a.k.a. ! gsl_CONFIG( NOT_NULL_GET_BY_CONST_REF ) + gsl_NODISCARD gsl_api gsl_constexpr14 T + get() const + { + return accessor::get_checked( *this ); + } +# endif // gsl_CONFIG( NOT_NULL_GET_BY_CONST_REF ) +#endif // ! gsl_CONFIG( TRANSPARENT_NOT_NULL ) + + // We want an implicit conversion operator that can be used to convert from both lvalues (by + // const reference or by copy) and rvalues (by move). So it seems like we could define + // + // template< class U > + // operator U const &() const & { ... } + // template< class U > + // operator U &&() && { ... } + // + // However, having two conversion operators with different return types renders the assignment + // operator of the result type ambiguous: + // + // not_null<std::unique_ptr<T>> p( ... ); + // std::unique_ptr<U> q; + // q = std::move( p ); // ambiguous + // + // To avoid this ambiguity, we have both overloads of the conversion operator return `U` + // rather than `U const &` or `U &&`. This implies that converting an lvalue always induces + // a copy, which can cause unnecessary copies or even fail to compile in some situations: + // + // not_null<std::shared_ptr<T>> sp( ... ); + // std::shared_ptr<U> const & rs = sp; // unnecessary copy + // std::unique_ptr<U> const & ru = p; // error: cannot copy `unique_ptr<T>` + // + // However, these situations are rather unusual, and the following, more frequent situations + // remain unimpaired: + // + // std::shared_ptr<U> vs = sp; // no extra copy + // std::unique_ptr<U> vu = std::move( p ); + +#if gsl_HAVE( MOVE_FORWARD ) && gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) && gsl_HAVE( EXPLICIT ) + // explicit conversion operator + + template< class U + // We *have* to use SFINAE with an NTTP arg here, otherwise the overload is ambiguous. + gsl_ENABLE_IF_NTTP_(( std::is_constructible<U, T const &>::value && !std::is_convertible<T, U>::value && !detail::is_not_null_or_bool_oracle<U>::value )) + > + gsl_NODISCARD gsl_api gsl_constexpr14 explicit + operator U() const +# if gsl_HAVE( FUNCTION_REF_QUALIFIER ) + & +# endif + { + return U( accessor::get_checked( *this ) ); + } +# if gsl_HAVE( FUNCTION_REF_QUALIFIER ) + template< class U + // We *have* to use SFINAE with an NTTP arg here, otherwise the overload is ambiguous. + gsl_ENABLE_IF_NTTP_(( std::is_constructible<U, T>::value && !std::is_convertible<T, U>::value && !detail::is_not_null_or_bool_oracle<U>::value )) + > + gsl_NODISCARD gsl_api gsl_constexpr14 explicit + operator U() && + { + return U( accessor::get_checked( std::move( *this ) ) ); + } +# endif + + // implicit conversion operator + template< class U + // We *have* to use SFINAE with an NTTP arg here, otherwise the overload is ambiguous. + gsl_ENABLE_IF_NTTP_(( std::is_constructible<U, T const &>::value && std::is_convertible<T, U>::value && !detail::is_not_null_or_bool_oracle<U>::value )) + > + gsl_NODISCARD gsl_api gsl_constexpr14 + operator U() const +# if gsl_HAVE( FUNCTION_REF_QUALIFIER ) + & +# endif + { + return accessor::get_checked( *this ); + } +# if gsl_HAVE( FUNCTION_REF_QUALIFIER ) + template< class U + // We *have* to use SFINAE with an NTTP arg here, otherwise the overload is ambiguous. + gsl_ENABLE_IF_NTTP_(( std::is_convertible<T, U>::value && !detail::is_not_null_or_bool_oracle<U>::value )) + > + gsl_NODISCARD gsl_api gsl_constexpr14 + operator U() && + { + return accessor::get_checked( std::move( *this ) ); + } +# endif +#else // a.k.a. #if !( gsl_HAVE( MOVE_FORWARD ) && gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) && gsl_HAVE( EXPLICIT ) ) + template< class U > + gsl_NODISCARD gsl_api gsl_constexpr14 + operator U() const + { + return U( accessor::get_checked( *this ) ); + } +#endif // gsl_HAVE( MOVE_FORWARD ) && gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) && gsl_HAVE( EXPLICIT ) + + gsl_NODISCARD gsl_api gsl_constexpr14 T const & + operator->() const + { + return accessor::get_checked( *this ); + } + +#if gsl_HAVE( MOVE_FORWARD ) + // Visual C++ 2013 doesn't generate default move constructors, so we declare them explicitly. + gsl_api gsl_constexpr14 not_null( not_null && other ) + gsl_noexcept_not_testing // we want to be nothrow-movable despite the assertion + : data_( std::move( other.data_ ) ) + { + } + gsl_api gsl_constexpr14 not_null & operator=( not_null && other ) + gsl_noexcept_not_testing // we want to be nothrow-movable despite the assertion + { + data_ = std::move( other.data_ ); + return *this; + } +#endif // gsl_HAVE( MOVE_FORWARD ) + +#if gsl_HAVE( IS_DEFAULT ) + gsl_constexpr14 not_null( not_null const & ) = default; + gsl_constexpr14 not_null & operator=( not_null const & ) = default; +#endif + + gsl_api gsl_constexpr20 friend void swap( not_null & lhs, not_null & rhs ) + gsl_noexcept_not_testing // we want to be nothrow-swappable despite the precondition check + { + accessor::check( lhs ); + accessor::check( rhs ); + using std::swap; + swap( lhs.data_.ptr_, rhs.data_.ptr_ ); + } + +gsl_is_delete_access: + not_null() gsl_is_delete; + // prevent compilation when initialized with a nullptr or literal 0: +#if gsl_HAVE( NULLPTR ) + not_null( std::nullptr_t ) gsl_is_delete; + not_null & operator=( std::nullptr_t ) gsl_is_delete; +#else + not_null( int ) gsl_is_delete; + not_null & operator=( int ) gsl_is_delete; +#endif + +#if gsl_STDLIB_CPP11_140 && ( gsl_CPP14_OR_GREATER || ! gsl_COMPILER_NVCC_VERSION ) + template< class... Ts > + gsl_api gsl_constexpr14 auto + operator()( Ts&&... args ) const +# if ! gsl_COMPILER_NVCC_VERSION + // NVCC thinks that Substitution Failure Is An Error here + -> decltype( data_.ptr_( std::forward<Ts>( args )... ) ) +# endif // ! gsl_COMPILER_NVCC_VERSION + { + return accessor::get_checked( *this )( std::forward<Ts>( args )... ); + } +#endif // gsl_STDLIB_CPP11_140 && ( gsl_CPP14_OR_GREATER || ! gsl_COMPILER_NVCC_VERSION ) + + // unwanted operators...pointers only point to single objects! + not_null & operator++() gsl_is_delete; + not_null & operator--() gsl_is_delete; + not_null operator++( int ) gsl_is_delete; + not_null operator--( int ) gsl_is_delete; + not_null & operator+ ( size_t ) gsl_is_delete; + not_null & operator+=( size_t ) gsl_is_delete; + not_null & operator- ( size_t ) gsl_is_delete; + not_null & operator-=( size_t ) gsl_is_delete; + not_null & operator+=( std::ptrdiff_t ) gsl_is_delete; + not_null & operator-=( std::ptrdiff_t ) gsl_is_delete; + void operator[]( std::ptrdiff_t ) const gsl_is_delete; +}; +#if gsl_HAVE( DEDUCTION_GUIDES ) +template< class U > +not_null( U ) -> not_null<U>; +template< class U > +not_null( not_null<U> ) -> not_null<U>; +#endif + +#if gsl_HAVE( NULLPTR ) +void make_not_null( std::nullptr_t ) gsl_is_delete; +#endif // gsl_HAVE( NULLPTR ) +#if gsl_HAVE( MOVE_FORWARD ) +template< class U > +gsl_NODISCARD gsl_api gsl_constexpr14 not_null<U> +make_not_null( U u ) +{ + return not_null<U>( std::move( u ) ); +} +template< class U > +gsl_NODISCARD gsl_api gsl_constexpr14 not_null<U> +make_not_null( not_null<U> u ) +{ + return std::move( u ); +} +#else // a.k.a. ! gsl_HAVE( MOVE_FORWARD ) +template< class U > +gsl_NODISCARD gsl_api not_null<U> +make_not_null( U const & u ) +{ + return not_null<U>( u ); +} +template< class U > +gsl_NODISCARD gsl_api not_null<U> +make_not_null( not_null<U> const & u ) +{ + return u; +} +#endif // gsl_HAVE( MOVE_FORWARD ) + +namespace detail { + +template< class T > +struct as_nullable_helper +{ + typedef T type; +}; +template< class T > +struct as_nullable_helper< not_null<T> > +{ +}; + +template< class T > +struct not_null_accessor +{ +#if gsl_HAVE( MOVE_FORWARD ) + static gsl_api T get( not_null<T>&& p ) gsl_noexcept + { + return std::move( p.data_.ptr_ ); + } + static gsl_api T get_checked( not_null<T>&& p ) + { + gsl_Assert( p.data_.ptr_ != gsl_nullptr ); + return std::move( p.data_.ptr_ ); + } +#endif + static gsl_api T const & get( not_null<T> const & p ) gsl_noexcept + { + return p.data_.ptr_; + } + static gsl_api bool is_valid( not_null<T> const & p ) gsl_noexcept + { + return p.data_.ptr_ != gsl_nullptr; + } + static gsl_api void check( not_null<T> const & p ) + { + gsl_Assert( p.data_.ptr_ != gsl_nullptr ); + } + static gsl_api T const & get_checked( not_null<T> const & p ) + { + gsl_Assert( p.data_.ptr_ != gsl_nullptr ); + return p.data_.ptr_; + } +}; +template< class T > +struct not_null_accessor< T * > +{ + static gsl_api T * const & get( not_null< T * > const & p ) gsl_noexcept + { + return p.data_.ptr_; + } + static gsl_api bool is_valid( not_null< T * > const & /*p*/ ) gsl_noexcept + { + return true; + } + static gsl_api void check( not_null< T * > const & /*p*/ ) + { + } + static gsl_api T * const & get_checked( not_null< T * > const & p ) gsl_noexcept + { + return p.data_.ptr_; + } +}; + +namespace no_adl { + +#if gsl_HAVE( MOVE_FORWARD ) +template< class T > +gsl_NODISCARD gsl_api gsl_constexpr auto as_nullable( T && p ) +gsl_noexcept_if( std::is_nothrow_move_constructible<T>::value ) +-> typename detail::as_nullable_helper<typename std20::remove_cvref<T>::type>::type +{ + return std::move( p ); +} +template< class T > +gsl_NODISCARD gsl_api gsl_constexpr14 T as_nullable( not_null<T> && p ) +{ + return detail::not_null_accessor<T>::get_checked( std::move( p ) ); +} +#else // ! gsl_HAVE( MOVE_FORWARD ) +template< class T > +gsl_NODISCARD gsl_api gsl_constexpr T const & as_nullable( T const & p ) gsl_noexcept +{ + return p; +} +#endif // gsl_HAVE( MOVE_FORWARD ) +template< class T > +gsl_NODISCARD gsl_api gsl_constexpr14 T const & +as_nullable( not_null<T> const & p ) +{ + return detail::not_null_accessor<T>::get_checked( p ); +} + +template< class T > +gsl_NODISCARD gsl_api gsl_constexpr bool +is_valid( not_null<T> const & p ) +{ + return detail::not_null_accessor<T>::is_valid( p ); +} + +} // namespace no_adl +} // namespace detail + +using namespace detail::no_adl; + +// not_null with implicit constructor, allowing copy-initialization: + +template< class T > +class not_null_ic : public not_null<T> +{ +public: + template< class U + gsl_ENABLE_IF_(( std::is_constructible<T, U>::value )) + > + gsl_api gsl_constexpr14 +#if gsl_HAVE( MOVE_FORWARD ) + not_null_ic( U u ) + : not_null<T>( std::move( u ) ) +#else // ! gsl_HAVE( MOVE_FORWARD ) + not_null_ic( U const & u ) + : not_null<T>( u ) +#endif // gsl_HAVE( MOVE_FORWARD ) + {} +}; + +// more not_null unwanted operators + +template< class T, class U > +std::ptrdiff_t operator-( not_null<T> const &, not_null<U> const & ) gsl_is_delete; + +template< class T > +not_null<T> operator-( not_null<T> const &, std::ptrdiff_t ) gsl_is_delete; + +template< class T > +not_null<T> operator+( not_null<T> const &, std::ptrdiff_t ) gsl_is_delete; + +template< class T > +not_null<T> operator+( std::ptrdiff_t, not_null<T> const & ) gsl_is_delete; + +// not_null comparisons + +#if gsl_HAVE( NULLPTR ) && gsl_HAVE( IS_DELETE ) +template< class T > +gsl_constexpr bool +operator==( not_null<T> const &, std::nullptr_t ) = delete; +template< class T > +gsl_constexpr bool +operator==( std::nullptr_t , not_null<T> const & ) = delete; +template< class T > +gsl_constexpr bool +operator!=( not_null<T> const &, std::nullptr_t ) = delete; +template< class T > +gsl_constexpr bool +operator!=( std::nullptr_t , not_null<T> const & ) = delete; +#endif // gsl_HAVE( NULLPTR ) && gsl_HAVE( IS_DELETE ) + +template< class T, class U > +gsl_NODISCARD inline gsl_api gsl_constexpr gsl_TRAILING_RETURN_TYPE_( bool ) +operator==( not_null<T> const & l, not_null<U> const & r ) +gsl_RETURN_DECLTYPE_( l.operator->() == r.operator->() ) +{ + return l.operator->() == r.operator->(); +} +template< class T, class U > +gsl_NODISCARD inline gsl_api gsl_constexpr gsl_TRAILING_RETURN_TYPE_( bool ) +operator==( not_null<T> const & l, U const & r ) +gsl_RETURN_DECLTYPE_(l.operator->() == r ) +{ + return l.operator->() == r; +} +#if ! gsl_CPP20_OR_GREATER +template< class T, class U > +gsl_NODISCARD inline gsl_api gsl_constexpr gsl_TRAILING_RETURN_TYPE_( bool ) +operator==( T const & l, not_null<U> const & r ) +gsl_RETURN_DECLTYPE_( l == r.operator->() ) +{ + return l == r.operator->(); +} +#endif // ! gsl_CPP20_OR_GREATER + +// The C++ Core Guidelines discourage the use of pointer arithmetic, and gsl-lite consequently refrains from defining operators +// for pointer arithmetic or the subscript operator in `not_null<>`. However, comparison of `not_null<>` objects is supported; +// although the standard does not mandate a certain ordering for objects with two exceptions (objects from the same array; +// data members of the same class, as required for `offsetof()`), it does require that `operator<` establishes a total ordering +// of pointers, as implied by https://eel.is/c++draft/expr.rel#5. Among other things, this guarantees that a list of pointers +// can be sorted and searched, or that pointers can be used as a key in a relational container such as `std::map<>`. +// Therefore, we also define relational comparison operators for `not_null<>`. + +#if gsl_STDLIB_CPP20_OR_GREATER +template< class T, class U > +[[nodiscard]] inline gsl_api constexpr auto +operator<=>( not_null<T> const & l, not_null<U> const & r ) +-> decltype( l.operator->() <=> r.operator->() ) +{ + return l.operator->() <=> r.operator->(); +} +template< class T, class U > +[[nodiscard]] inline gsl_api constexpr auto +operator<=>( not_null<T> const & l, U const & r ) +-> decltype( l.operator->() <=> r ) +{ + return l.operator->() <=> r; +} +#endif // gsl_STDLIB_CPP20_OR_GREATER +template< class T, class U > +gsl_NODISCARD inline gsl_api gsl_constexpr gsl_TRAILING_RETURN_TYPE_( bool ) +operator<( not_null<T> const & l, not_null<U> const & r ) +gsl_RETURN_DECLTYPE_( l.operator->() < r.operator->() ) +{ + return l.operator->() < r.operator->(); +} +template< class T, class U > +gsl_NODISCARD inline gsl_api gsl_constexpr gsl_TRAILING_RETURN_TYPE_( bool ) +operator<( not_null<T> const & l, U const & r ) +gsl_RETURN_DECLTYPE_( l.operator->() < r ) +{ + return l.operator->() < r; +} +template< class T, class U > +gsl_NODISCARD inline gsl_api gsl_constexpr gsl_TRAILING_RETURN_TYPE_( bool ) +operator<( T const & l, not_null<U> const & r ) +gsl_RETURN_DECLTYPE_( l < r.operator->() ) +{ + return l < r.operator->(); +} + +#if ! gsl_CPP20_OR_GREATER +template< class T, class U > +gsl_NODISCARD inline gsl_api gsl_constexpr gsl_TRAILING_RETURN_TYPE_( bool ) +operator!=( not_null<T> const & l, not_null<U> const & r ) +gsl_RETURN_DECLTYPE_( !( l == r ) ) +{ + return !( l == r ); +} +template< class T, class U > +gsl_NODISCARD inline gsl_api gsl_constexpr gsl_TRAILING_RETURN_TYPE_( bool ) +operator!=( not_null<T> const & l, U const & r ) +gsl_RETURN_DECLTYPE_( !( l == r ) ) +{ + return !( l == r ); +} +template< class T, class U > +gsl_NODISCARD inline gsl_api gsl_constexpr gsl_TRAILING_RETURN_TYPE_( bool ) +operator!=( T const & l, not_null<U> const & r ) +gsl_RETURN_DECLTYPE_( !( l == r ) ) +{ + return !( l == r ); +} +#endif // ! gsl_CPP20_OR_GREATER + +template< class T, class U > +gsl_NODISCARD inline gsl_api gsl_constexpr gsl_TRAILING_RETURN_TYPE_( bool ) +operator<=( not_null<T> const & l, not_null<U> const & r ) +gsl_RETURN_DECLTYPE_( !( r < l ) ) +{ + return !( r < l ); +} +template< class T, class U > +gsl_NODISCARD inline gsl_api gsl_constexpr gsl_TRAILING_RETURN_TYPE_( bool ) +operator<=( not_null<T> const & l, U const & r ) +gsl_RETURN_DECLTYPE_( !( r < l ) ) +{ + return !( r < l ); +} +template< class T, class U > +gsl_NODISCARD inline gsl_api gsl_constexpr gsl_TRAILING_RETURN_TYPE_( bool ) +operator<=( T const & l, not_null<U> const & r ) +gsl_RETURN_DECLTYPE_( !( r < l ) ) +{ + return !( r < l ); +} + +template< class T, class U > +gsl_NODISCARD inline gsl_api gsl_constexpr gsl_TRAILING_RETURN_TYPE_( bool ) +operator>( not_null<T> const & l, not_null<U> const & r ) +gsl_RETURN_DECLTYPE_( r < l ) +{ + return r < l; +} +template< class T, class U > +gsl_NODISCARD inline gsl_api gsl_constexpr gsl_TRAILING_RETURN_TYPE_( bool ) +operator>( not_null<T> const & l, U const & r ) +gsl_RETURN_DECLTYPE_( r < l ) +{ + return r < l; +} +template< class T, class U > +gsl_NODISCARD inline gsl_api gsl_constexpr gsl_TRAILING_RETURN_TYPE_( bool ) +operator>( T const & l, not_null<U> const & r ) +gsl_RETURN_DECLTYPE_( r < l ) +{ + return r < l; +} + +template< class T, class U > +gsl_NODISCARD inline gsl_api gsl_constexpr gsl_TRAILING_RETURN_TYPE_( bool ) +operator>=( not_null<T> const & l, not_null<U> const & r ) +gsl_RETURN_DECLTYPE_( !( l < r ) ) +{ + return !( l < r ); +} +template< class T, class U > +gsl_NODISCARD inline gsl_api gsl_constexpr gsl_TRAILING_RETURN_TYPE_( bool ) +operator>=( not_null<T> const & l, U const & r ) +gsl_RETURN_DECLTYPE_( !( l < r ) ) +{ + return !( l < r ); +} +template< class T, class U > +gsl_NODISCARD inline gsl_api gsl_constexpr gsl_TRAILING_RETURN_TYPE_( bool ) +operator>=( T const & l, not_null<U> const & r ) +gsl_RETURN_DECLTYPE_( !( l < r ) ) +{ + return !( l < r ); +} + +// print not_null + +template< class CharType, class Traits, class T > +std::basic_ostream< CharType, Traits > & operator<<( std::basic_ostream< CharType, Traits > & os, not_null<T> const & p ) +{ + return os << p.operator->(); +} + + +#if gsl_HAVE( VARIADIC_TEMPLATE ) +# if gsl_HAVE( UNIQUE_PTR ) +template< class T, class... Args > +gsl_NODISCARD not_null<std::unique_ptr<T>> +make_unique( Args &&... args ) +{ +# if gsl_HAVE( TYPE_TRAITS ) + static_assert( !std::is_array<T>::value, "gsl_lite::make_unique<T>() returns `gsl_lite::not_null<std::unique_ptr<T>>`, which is not " + "defined for array types because the Core Guidelines advise against pointer arithmetic, cf. \"Bounds safety profile\"." ); +# endif + return not_null<std::unique_ptr<T>>( new T( std::forward<Args>( args )... ) ); +} +# endif // gsl_HAVE( UNIQUE_PTR ) +# if gsl_HAVE( SHARED_PTR ) +template< class T, class... Args > +gsl_NODISCARD not_null<std::shared_ptr<T>> +make_shared( Args &&... args ) +{ +# if gsl_HAVE( TYPE_TRAITS ) + static_assert( !std::is_array<T>::value, "gsl_lite::make_shared<T>() returns `gsl_lite::not_null<std::shared_ptr<T>>`, which is not " + "defined for array types because the Core Guidelines advise against pointer arithmetic, cf. \"Bounds safety profile\"." ); +# endif + return not_null<std::shared_ptr<T>>( std::make_shared<T>( std::forward<Args>( args )... ) ); +} +# endif // gsl_HAVE( SHARED_PTR ) +#endif // gsl_HAVE( VARIADIC_TEMPLATE ) + + +#if gsl_FEATURE( BYTE ) +// +// Byte-specific type. +// +# if gsl_HAVE( ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE ) + enum class gsl_may_alias byte : unsigned char {}; +# else +# if ! defined( gsl_CONFIG_ACKNOWLEDGE_NONSTANDARD_ABI ) +# pragma message (__FILE__ "(" gsl_STRINGIFY( __LINE__ ) "): warning: in pre-C++11 mode, byte is defined as a struct rather than an enum, which changes the ABI of gsl-lite and may lead to ODR violations and undefined behavior; define the macro gsl_CONFIG_ACKNOWLEDGE_NONSTANDARD_ABI to explicitly acknowledge that you are using gsl-lite with a non-standard ABI and that you control the build flags of all components linked into your target") +# endif + struct gsl_may_alias byte { typedef unsigned char type; type v; }; +# endif + +template< class T > +gsl_NODISCARD gsl_api inline gsl_constexpr byte +to_byte( T v ) gsl_noexcept +{ +# if gsl_HAVE( ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE ) + return static_cast<byte>( v ); +# elif gsl_HAVE( CONSTEXPR_11 ) + return { static_cast<typename byte::type>( v ) }; +# else + byte b = { static_cast<typename byte::type>( v ) }; return b; +# endif +} + +template< class IntegerType gsl_ENABLE_IF_(( std::is_integral<IntegerType>::value )) > +gsl_NODISCARD gsl_api inline gsl_constexpr IntegerType +to_integer( byte b ) gsl_noexcept +{ +# if gsl_HAVE( ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE ) + return static_cast<typename std::underlying_type<byte>::type>( b ); +# else + return b.v; +# endif +} + +gsl_NODISCARD gsl_api inline gsl_constexpr unsigned char +to_uchar( byte b ) gsl_noexcept +{ + return to_integer<unsigned char>( b ); +} + +gsl_NODISCARD gsl_api inline gsl_constexpr unsigned char +to_uchar( int i ) gsl_noexcept +{ + return static_cast<unsigned char>( i ); +} + +template< class IntegerType gsl_ENABLE_IF_(( std::is_integral<IntegerType>::value )) > +gsl_api inline gsl_constexpr14 byte & +operator<<=( byte & b, IntegerType shift ) gsl_noexcept +{ +# if gsl_HAVE( ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE ) + return b = ::gsl_lite::to_byte( ::gsl_lite::to_uchar( b ) << shift ); +# else + b.v = ::gsl_lite::to_uchar( b.v << shift ); return b; +# endif +} + +template< class IntegerType gsl_ENABLE_IF_(( std::is_integral<IntegerType>::value )) > +gsl_NODISCARD gsl_api inline gsl_constexpr byte +operator<<( byte b, IntegerType shift ) gsl_noexcept +{ + return ::gsl_lite::to_byte( ::gsl_lite::to_uchar( b ) << shift ); +} + +template< class IntegerType gsl_ENABLE_IF_(( std::is_integral<IntegerType>::value )) > +gsl_NODISCARD gsl_api inline gsl_constexpr14 byte & +operator>>=( byte & b, IntegerType shift ) gsl_noexcept +{ +# if gsl_HAVE( ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE ) + return b = ::gsl_lite::to_byte( ::gsl_lite::to_uchar( b ) >> shift ); +# else + b.v = ::gsl_lite::to_uchar( b.v >> shift ); return b; +# endif +} + +template< class IntegerType gsl_ENABLE_IF_(( std::is_integral<IntegerType>::value )) > +gsl_NODISCARD gsl_api inline gsl_constexpr byte +operator>>( byte b, IntegerType shift ) gsl_noexcept +{ + return ::gsl_lite::to_byte( ::gsl_lite::to_uchar( b ) >> shift ); +} + +# if gsl_HAVE( ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE ) +gsl_DEFINE_ENUM_BITMASK_OPERATORS( byte ) +gsl_DEFINE_ENUM_RELATIONAL_OPERATORS( byte ) +# else // a.k.a. !gsl_HAVE( ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE ) +gsl_api inline gsl_constexpr bool operator==( byte l, byte r ) gsl_noexcept +{ + return l.v == r.v; +} + +gsl_api inline gsl_constexpr bool operator!=( byte l, byte r ) gsl_noexcept +{ + return !( l == r ); +} + +gsl_api inline gsl_constexpr bool operator< ( byte l, byte r ) gsl_noexcept +{ + return l.v < r.v; +} + +gsl_api inline gsl_constexpr bool operator<=( byte l, byte r ) gsl_noexcept +{ + return !( r < l ); +} + +gsl_api inline gsl_constexpr bool operator> ( byte l, byte r ) gsl_noexcept +{ + return ( r < l ); +} + +gsl_api inline gsl_constexpr bool operator>=( byte l, byte r ) gsl_noexcept +{ + return !( l < r ); +} + +gsl_api inline gsl_constexpr14 byte & operator|=( byte & l, byte r ) gsl_noexcept +{ + l.v |= r.v; return l; +} + +gsl_api inline gsl_constexpr byte operator|( byte l, byte r ) gsl_noexcept +{ + return ::gsl_lite::to_byte( l.v | r.v ); +} + +gsl_api inline gsl_constexpr14 byte & operator&=( byte & l, byte r ) gsl_noexcept +{ + l.v &= r.v; return l; +} + +gsl_api inline gsl_constexpr byte operator&( byte l, byte r ) gsl_noexcept +{ + return ::gsl_lite::to_byte( l.v & r.v ); +} + +gsl_api inline gsl_constexpr14 byte & operator^=( byte & l, byte r ) gsl_noexcept +{ + l.v ^= r.v; return l; +} + +gsl_api inline gsl_constexpr byte operator^( byte l, byte r ) gsl_noexcept +{ + return ::gsl_lite::to_byte( l.v ^ r.v ); +} + +gsl_api inline gsl_constexpr byte operator~( byte b ) gsl_noexcept +{ + return ::gsl_lite::to_byte( ~b.v ); +} +# endif // gsl_HAVE( ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE ) +#endif // gsl_FEATURE( BYTE ) + +#if gsl_FEATURE_TO_STD( WITH_CONTAINER ) + +// Tag to select span constructor taking a container: + +struct with_container_t { gsl_constexpr with_container_t( ) gsl_noexcept { } }; +const gsl_constexpr with_container_t with_container; // TODO: this can lead to ODR violations because the symbol will be defined in multiple translation units + +#endif + + +// The span<> and span_iterator<> implementation below was mostly borrowed from Microsoft GSL. + + +#if gsl_COMPILER_MSVC_VER +# pragma warning( push ) + +// turn off some warnings that are noisy about our Expects statements +# pragma warning( disable : 4127 ) // conditional expression is constant +# pragma warning( disable : 4146 ) // unary minus operator applied to unsigned type, result still unsigned +# pragma warning( disable : 4702 ) // unreachable code + +// Turn off MSVC /analyze rules that generate too much noise +# pragma warning( disable : 26495 ) // uninitialized member when constructor calls constructor +# pragma warning( disable : 26446 ) // parser bug does not allow attributes on some templates + +#endif // gsl_COMPILER_MSVC_VER + +// 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 +// and only warn in those cases. +#if defined( __GNUC__ ) && __GNUC__ > 6 +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wsign-conversion" +#endif // defined( __GNUC__ ) && __GNUC__ > 6 + +// 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 detail { + +template< class T > +gsl_api gsl_constexpr14 T * endptr( T * data, gsl_CONFIG_SPAN_INDEX_TYPE size ) // TODO: remove? +{ + // Be sure to run the check before doing pointer arithmetics, which would be UB for `nullptr` and non-0 integers. + gsl_Expects( size == 0 || data != gsl_nullptr ); + return data + size; +} + +template< gsl_CONFIG_SPAN_INDEX_TYPE From, gsl_CONFIG_SPAN_INDEX_TYPE To > +struct is_allowed_extent_conversion + : std17::bool_constant< From == To || To == dynamic_extent > +{ +}; + +#if gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) +template< class From, class To > +struct is_allowed_element_type_conversion + : std17::bool_constant< std::is_convertible< From (*)[], To (*)[] >::value > +{ +}; +#endif // gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) + +template< class T > +class span_iterator +{ +public: +#if gsl_STDLIB_CPP20_OR_GREATER + typedef typename std::contiguous_iterator_tag iterator_concept; +#endif // gsl_STDLIB_CPP20_OR_GREATER + typedef typename std::random_access_iterator_tag iterator_category; + typedef typename std11::remove_cv< T >::type value_type; + typedef std::ptrdiff_t difference_type; + typedef T * pointer; + typedef T & reference; + +#ifdef _MSC_VER + typedef pointer _Unchecked_type; + typedef span_iterator _Prevent_inheriting_unwrap; +#endif // _MSC_VER +#if gsl_HAVE( IS_DEFAULT ) + gsl_constexpr span_iterator() = default; +#else // ! gsl_HAVE( IS_DEFAULT ) + gsl_api gsl_constexpr span_iterator() gsl_noexcept + : begin_( gsl_nullptr ), end_( gsl_nullptr ), current_( gsl_nullptr ) + { + } +#endif // gsl_HAVE( IS_DEFAULT ) + + gsl_api gsl_constexpr14 span_iterator( pointer begin, pointer end, pointer current ) + : begin_( begin ), end_( end ), current_( current ) + { + gsl_ExpectsDebug( begin_ <= current_ && current <= end_ ); + } + + gsl_api gsl_constexpr14 operator span_iterator< T const >() const gsl_noexcept + { + return span_iterator< T const >( begin_, end_, current_ ); + } + + gsl_api gsl_constexpr14 reference operator*() const + { + gsl_ExpectsDebug( current_ != end_ ); + return *current_; + } + + gsl_api gsl_constexpr14 pointer operator->() const + { + gsl_ExpectsDebug( current_ != end_ ); + return current_; + } + gsl_api gsl_constexpr14 span_iterator& operator++() + { + gsl_ExpectsDebug( current_ != end_ ); + gsl_SUPPRESS_MSGSL_WARNING(bounds.1) + ++current_; + return *this; + } + + gsl_api gsl_constexpr14 span_iterator operator++( int ) + { + span_iterator ret = *this; + ++*this; + return ret; + } + + gsl_api gsl_constexpr14 span_iterator& operator--() + { + gsl_ExpectsDebug( begin_ != current_ ); + --current_; + return *this; + } + + gsl_api gsl_constexpr14 span_iterator operator--( int ) + { + span_iterator ret = *this; + --*this; + return ret; + } + + gsl_api gsl_constexpr14 span_iterator& operator+=( difference_type const n ) + { + if ( n != 0 ) gsl_ExpectsDebug( begin_ && current_ && end_ ); + if ( n > 0 ) gsl_ExpectsDebug( end_ - current_ >= n ); + if ( n < 0 ) gsl_ExpectsDebug( current_ - begin_ >= -n ); + gsl_SUPPRESS_MSGSL_WARNING(bounds.1) + current_ += n; + return *this; + } + + gsl_api gsl_constexpr14 span_iterator operator+( difference_type const n ) const + { + span_iterator ret = *this; + ret += n; + return ret; + } + + friend gsl_api gsl_constexpr14 span_iterator operator+( difference_type const n, + span_iterator const & rhs ) + { + return rhs + n; + } + + gsl_api gsl_constexpr14 span_iterator& operator-=( difference_type const n ) + { + if ( n != 0 ) gsl_ExpectsDebug( begin_ && current_ && end_ ); + if ( n > 0 ) gsl_ExpectsDebug( current_ - begin_ >= n ); + if ( n < 0 ) gsl_ExpectsDebug( end_ - current_ >= -n ); + gsl_SUPPRESS_MSGSL_WARNING(bounds .1) + current_ -= n; + return *this; + } + + gsl_api gsl_constexpr14 span_iterator operator-( difference_type const n ) const + { + span_iterator ret = *this; + ret -= n; + return ret; + } + + template< + class U + gsl_ENABLE_IF_(( std::is_same< typename std::remove_cv< U >::type, value_type >::value )) + > + gsl_api gsl_constexpr14 difference_type operator-( span_iterator< U > const & rhs ) const + { + gsl_ExpectsDebug( begin_ == rhs.begin_ && end_ == rhs.end_ ); + return current_ - rhs.current_; + } + + gsl_api gsl_constexpr14 reference operator[]( difference_type const n ) const + { + return *( *this + n ); + } + + template < + class U + gsl_ENABLE_IF_(( std::is_same< typename std::remove_cv< U >::type, value_type >::value )) + > + gsl_api gsl_constexpr14 bool operator==( span_iterator< U > const & rhs ) const + { + gsl_ExpectsDebug( begin_ == rhs.begin_ && end_ == rhs.end_ ); + return current_ == rhs.current_; + } + + template < + class U + gsl_ENABLE_IF_(( std::is_same< typename std::remove_cv< U >::type, value_type >::value )) + > + gsl_api gsl_constexpr14 bool operator!=( span_iterator< U > const & rhs ) const + { + return !( *this == rhs ); + } + + template < + class U + gsl_ENABLE_IF_(( std::is_same< typename std::remove_cv< U >::type, value_type >::value )) + > + gsl_api gsl_constexpr14 bool operator<( span_iterator< U > const & rhs ) const + { + gsl_ExpectsDebug( begin_ == rhs.begin_ && end_ == rhs.end_ ); + return current_ < rhs.current_; + } + + template < + class U + gsl_ENABLE_IF_(( std::is_same< typename std::remove_cv< U >::type, value_type >::value )) + > + gsl_api gsl_constexpr14 bool operator>( span_iterator< U > const & rhs ) const + { + return rhs < *this; + } + + template < + class U + gsl_ENABLE_IF_(( std::is_same< typename std::remove_cv< U >::type, value_type >::value )) + > + gsl_api gsl_constexpr14 bool operator<=( span_iterator< U > const & rhs ) const + { + return !( rhs < *this ); + } + + template < + class U + gsl_ENABLE_IF_(( std::is_same< typename std::remove_cv< U >::type, value_type >::value )) + > + gsl_api gsl_constexpr14 bool operator>=( span_iterator< U > const & rhs ) const + { + return !( *this < rhs ); + } + +#ifdef _MSC_VER + // MSVC++ iterator debugging support; allows STL algorithms in 15.8+ + // to unwrap span_iterator to a pointer type after a range check in STL + // algorithm calls. + friend gsl_api gsl_constexpr14 void _Verify_range( span_iterator lhs, span_iterator rhs ) gsl_noexcept + { + // test that [lhs, rhs) forms a valid range inside an STL algorithm + gsl_Expects( lhs.begin_ == rhs.begin_ // range spans have to match + && lhs.end_ == rhs.end_ && + lhs.current_ <= rhs.current_ ); // range must not be transposed + } + + gsl_api gsl_constexpr14 void _Verify_offset( difference_type const n ) const gsl_noexcept + { + // test that *this + n is within the range of this call + if ( n != 0 ) gsl_Expects( begin_ && current_ && end_ ); + if ( n > 0 ) gsl_Expects( end_ - current_ >= n ); + if ( n < 0 ) gsl_Expects( current_ - begin_ >= -n ); + } + + gsl_SUPPRESS_MSGSL_WARNING(bounds.1) + gsl_api gsl_constexpr14 pointer _Unwrapped() const gsl_noexcept + { + // after seeking *this to a high water mark, or using one of the + // _Verify_xxx functions above, unwrap this span_iterator to a raw + // pointer + return current_; + } + + // Tell the STL that span_iterator should not be unwrapped if it can't + // validate in advance, even in release / optimized builds: +# if gsl_CPP17_OR_GREATER + static constexpr bool _Unwrap_when_unverified = false; +# else + static gsl_constexpr const bool _Unwrap_when_unverified = false; +# endif + gsl_SUPPRESS_MSGSL_WARNING(con.3) // TODO: false positive + gsl_api gsl_constexpr14 void _Seek_to( pointer const p ) gsl_noexcept + { + // adjust the position of *this to previously verified location p + // after _Unwrapped + current_ = p; + } +#endif + +#if gsl_HAVE( IS_DEFAULT ) + pointer begin_ = nullptr; + pointer end_ = nullptr; + pointer current_ = nullptr; +#else // ! gsl_HAVE( IS_DEFAULT ) + pointer begin_; + pointer end_; + pointer current_; +#endif // gsl_HAVE( IS_DEFAULT ) + +#if gsl_STDLIB_CPP11_OR_GREATER + template< class Ptr > + friend struct std::pointer_traits; +#endif // gsl_STDLIB_CPP11_OR_GREATER +}; + +template< gsl_CONFIG_SPAN_INDEX_TYPE Ext > +class extent_type +{ +public: + typedef gsl_CONFIG_SPAN_INDEX_TYPE size_type; + +#if gsl_HAVE( IS_DEFAULT ) + gsl_constexpr extent_type() gsl_noexcept = default; +#else // ! gsl_HAVE( IS_DEFAULT ) + gsl_constexpr extent_type() gsl_noexcept { } +#endif // gsl_HAVE( IS_DEFAULT ) + + gsl_api gsl_constexpr14 gsl_explicit extent_type( extent_type< dynamic_extent > ); + + gsl_api gsl_constexpr14 gsl_explicit extent_type( size_type size ) { gsl_Expects( size == Ext ); } + + gsl_api gsl_constexpr size_type size() const gsl_noexcept { return Ext; } + +private: +#if gsl_CPP17_OR_GREATER + static constexpr size_type size_ = Ext; // static size equal to Ext +#else + static gsl_constexpr const size_type size_ = Ext; // static size equal to Ext +#endif +}; + +template<> +class extent_type< dynamic_extent > +{ +public: + typedef gsl_CONFIG_SPAN_INDEX_TYPE size_type; + + template< size_type Other > + gsl_api gsl_constexpr gsl_explicit extent_type( extent_type< Other > ext ) + : size_( ext.size() ) + { + } + + gsl_api gsl_constexpr14 gsl_explicit extent_type( size_type size ) + : size_( size ) + { + gsl_Expects( size != dynamic_extent ); + } + + gsl_api gsl_constexpr size_type size() const gsl_noexcept { return size_; } + +private: + size_type size_; +}; + +template< gsl_CONFIG_SPAN_INDEX_TYPE Ext > +gsl_api gsl_constexpr14 extent_type< Ext >::extent_type( extent_type< dynamic_extent > ext ) +{ + gsl_Expects( ext.size() == Ext ); +} + +template< class T, gsl_CONFIG_SPAN_INDEX_TYPE Extent, gsl_CONFIG_SPAN_INDEX_TYPE Offset, gsl_CONFIG_SPAN_INDEX_TYPE Count > +struct calculate_subspan_type +{ + typedef span< T, Count != dynamic_extent + ? Count + : ( Extent != dynamic_extent ? Extent - Offset : Extent ) > type; +}; + +template< class T, class U, gsl_CONFIG_SPAN_INDEX_TYPE Extent, bool StaticExtent > +struct calculate_recast_span_type_0 +{ + typedef span< U, dynamic_extent > type; +}; +template< class T, class U, gsl_CONFIG_SPAN_INDEX_TYPE Extent > +struct calculate_recast_span_type_0< T, U, Extent, true > +{ + typedef span< U, Extent * sizeof( T ) / sizeof( U ) > type; +}; +template< class T, class U, gsl_CONFIG_SPAN_INDEX_TYPE Extent > +struct calculate_recast_span_type : calculate_recast_span_type_0< T, U, Extent, Extent != dynamic_extent > +{ +}; + +} // namespace detail + +// [span], class template span +template< class T, gsl_CONFIG_SPAN_INDEX_TYPE Extent > +class span +{ +public: + // constants and types + typedef T element_type; + typedef typename std11::remove_cv< T >::type value_type; + typedef gsl_CONFIG_SPAN_INDEX_TYPE size_type; + typedef gsl_CONFIG_SPAN_INDEX_TYPE index_type; + typedef element_type * pointer; + typedef element_type const * const_pointer; + typedef element_type & reference; + typedef element_type const & const_reference; + typedef std::ptrdiff_t difference_type; + + typedef detail::span_iterator< T > iterator; + typedef detail::span_iterator< T const > const_iterator; + typedef std::reverse_iterator< iterator > reverse_iterator; + typedef std::reverse_iterator< const_iterator > const_reverse_iterator; + +#if gsl_CPP17_OR_GREATER + static constexpr size_type extent{ Extent }; +#else + static gsl_constexpr const size_type extent = Extent; +#endif + + // [span.cons], span constructors, copy, assignment, and destructor +#if gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) + template< + gsl_CONFIG_SPAN_INDEX_TYPE MyExtent = Extent + // We *have* to use SFINAE with an NTTP arg here, otherwise the overload is ambiguous. + gsl_ENABLE_IF_NTTP_(( detail::is_allowed_extent_conversion< 0, MyExtent >::value )) + > +#endif // gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) + gsl_api gsl_constexpr span() gsl_noexcept + : storage_( detail::extent_type< 0 >( ) ) + { + } + +#if gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) && ! gsl_BETWEEN( gsl_COMPILER_MSVC_VERSION, 1, 140 ) + template< + gsl_CONFIG_SPAN_INDEX_TYPE MyExtent = Extent + // We *have* to use SFINAE with an NTTP arg here, otherwise the overload is ambiguous. + gsl_ENABLE_IF_NTTP_(( MyExtent != dynamic_extent )) + > + gsl_api gsl_constexpr14 gsl_explicit span( pointer ptr, size_type count ) + : storage_( ptr, count ) + { + gsl_Expects( count == Extent ); + } + template< + gsl_CONFIG_SPAN_INDEX_TYPE MyExtent = Extent + // We *have* to use SFINAE with an NTTP arg here, otherwise the overload is ambiguous. + gsl_ENABLE_IF_NTTP_(( MyExtent == dynamic_extent )) + > + gsl_api gsl_constexpr14 span( pointer ptr, size_type count ) + : storage_( ptr, count ) + { + } + + template< + gsl_CONFIG_SPAN_INDEX_TYPE MyExtent = Extent + // We *have* to use SFINAE with an NTTP arg here, otherwise the overload is ambiguous. + gsl_ENABLE_IF_NTTP_(( MyExtent != dynamic_extent )) + > + gsl_api gsl_constexpr14 gsl_explicit span( iterator it, size_type count ) + : storage_( it.current_, count ) + { + gsl_Expects( count == Extent ); + gsl_Expects( it.end_ - it.current_ == static_cast< difference_type >( Extent ) ); + } + template< + gsl_CONFIG_SPAN_INDEX_TYPE MyExtent = Extent + // We *have* to use SFINAE with an NTTP arg here, otherwise the overload is ambiguous. + gsl_ENABLE_IF_NTTP_(( MyExtent == dynamic_extent )) + > + gsl_api gsl_constexpr14 span( iterator it, size_type count ) + : storage_( it.current_, count ) + { + gsl_Expects( it.end_ - it.current_ >= static_cast< difference_type >( count ) ); + } + + template< + gsl_CONFIG_SPAN_INDEX_TYPE MyExtent = Extent + // We *have* to use SFINAE with an NTTP arg here, otherwise the overload is ambiguous. + gsl_ENABLE_IF_NTTP_(( MyExtent != dynamic_extent )) + > + gsl_api gsl_constexpr14 gsl_explicit span( pointer firstElem, pointer lastElem ) + : storage_( firstElem, gsl_lite::narrow_cast< size_type >( lastElem - firstElem ) ) + { + gsl_Expects( lastElem - firstElem == static_cast< difference_type >( Extent ) ); + } + template< + gsl_CONFIG_SPAN_INDEX_TYPE MyExtent = Extent + // We *have* to use SFINAE with an NTTP arg here, otherwise the overload is ambiguous. + gsl_ENABLE_IF_NTTP_(( MyExtent == dynamic_extent )) + > + gsl_api gsl_constexpr14 span( pointer firstElem, pointer lastElem ) + : storage_( firstElem, gsl_lite::narrow_cast< size_type >( lastElem - firstElem ) ) + { + gsl_Expects( firstElem <= lastElem ); + } + + template< + gsl_CONFIG_SPAN_INDEX_TYPE MyExtent = Extent + // We *have* to use SFINAE with an NTTP arg here, otherwise the overload is ambiguous. + gsl_ENABLE_IF_NTTP_(( MyExtent != dynamic_extent )) + > + gsl_api gsl_constexpr14 gsl_explicit span( iterator firstElem, iterator lastElem ) + : storage_( firstElem.current_, gsl_lite::narrow_cast< size_type >( lastElem - firstElem ) ) + { + gsl_Expects( lastElem - firstElem == static_cast< difference_type >( Extent ) ); + } + template< + gsl_CONFIG_SPAN_INDEX_TYPE MyExtent = Extent + // We *have* to use SFINAE with an NTTP arg here, otherwise the overload is ambiguous. + gsl_ENABLE_IF_NTTP_(( MyExtent == dynamic_extent )) + > + gsl_api gsl_constexpr14 span( iterator firstElem, iterator lastElem ) + : storage_( firstElem.current_, gsl_lite::narrow_cast< size_type >( lastElem - firstElem ) ) + { + gsl_Expects( firstElem <= lastElem ); + } +#else // !( gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) && ! gsl_BETWEEN( gsl_COMPILER_MSVC_VERSION, 1, 140 ) ) + gsl_api gsl_constexpr14 span( pointer ptr, size_type count ) + : storage_( ptr, count ) + { + gsl_Expects( Extent == dynamic_extent || count == Extent ); + } + gsl_api gsl_constexpr14 span( iterator it, size_type count ) + : storage_( it.current_, count ) + { + gsl_Expects( Extent == dynamic_extent || count == Extent ); + gsl_Expects( it.end_ - it.current_ >= static_cast< difference_type >( count ) ); + } + gsl_api gsl_constexpr14 span( pointer firstElem, pointer lastElem ) + : storage_( firstElem, gsl_lite::narrow_cast< size_type >( lastElem - firstElem ) ) + { + gsl_Expects( firstElem <= lastElem ); + gsl_Expects( Extent == dynamic_extent || lastElem - firstElem == static_cast< difference_type >( Extent ) ); + } + gsl_api gsl_constexpr14 span( iterator firstElem, iterator lastElem ) + : storage_( firstElem.current_, gsl_lite::narrow_cast< size_type >( lastElem - firstElem ) ) + { + gsl_Expects( firstElem <= lastElem ); + gsl_Expects( Extent == dynamic_extent || lastElem - firstElem == static_cast< difference_type >( Extent ) ); + } +#endif // gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) && ! gsl_BETWEEN( gsl_COMPILER_MSVC_VERSION, 1, 140 ) + + template< + class U, std::size_t N + gsl_ENABLE_IF_(( detail::is_allowed_extent_conversion< N, Extent >::value && + detail::is_allowed_element_type_conversion< U, element_type >::value )) + > + gsl_api gsl_constexpr span( U (&arr)[N] ) gsl_noexcept + : storage_( known_not_null( arr ), detail::extent_type< N >( ) ) + { + } + +#if gsl_HAVE( ARRAY ) + template< + class U, std::size_t N + gsl_ENABLE_IF_(( detail::is_allowed_extent_conversion< N, Extent >::value && + detail::is_allowed_element_type_conversion< U, element_type >::value )) + > + gsl_api gsl_constexpr span( std::array<U, N> & arr ) gsl_noexcept + : storage_( known_not_null( arr.data() ), detail::extent_type< N >( ) ) + { + } + template< + class U, std::size_t N + gsl_ENABLE_IF_(( detail::is_allowed_extent_conversion< N, Extent >::value && + detail::is_allowed_element_type_conversion< U const , element_type >::value )) + > + gsl_api gsl_constexpr span( std::array<U, N> const & arr ) gsl_noexcept + : storage_( known_not_null( arr.data() ), detail::extent_type< N >( ) ) + { + } +#endif // gsl_HAVE( ARRAY ) + +#if gsl_HAVE( CONSTRAINED_SPAN_CONTAINER_CTOR ) +# if ! gsl_BETWEEN( gsl_COMPILER_MSVC_VERSION, 1, 140 ) + template< class Container, gsl_CONFIG_SPAN_INDEX_TYPE MyExtent = Extent + // We *have* to use SFINAE with an NTTP arg here, otherwise the overload is ambiguous. + gsl_ENABLE_IF_NTTP_(( MyExtent != dynamic_extent && + detail::is_compatible_container< Container, element_type >::value )) + > + gsl_api gsl_constexpr gsl_explicit span( Container & cont ) gsl_noexcept + : storage_( std17::data( cont ), std17::size( cont ) ) + { + } + template< class Container, gsl_CONFIG_SPAN_INDEX_TYPE MyExtent = Extent + // We *have* to use SFINAE with an NTTP arg here, otherwise the overload is ambiguous. + gsl_ENABLE_IF_NTTP_(( MyExtent == dynamic_extent && + detail::is_compatible_container< Container, element_type >::value )) + > + gsl_api gsl_constexpr span( Container & cont ) gsl_noexcept + : storage_( std17::data( cont ), std17::size( cont ) ) + { + } + + template< class Container, gsl_CONFIG_SPAN_INDEX_TYPE MyExtent = Extent + // We *have* to use SFINAE with an NTTP arg here, otherwise the overload is ambiguous. + gsl_ENABLE_IF_NTTP_(( MyExtent != dynamic_extent && + std::is_const< element_type >::value && + detail::is_compatible_container< Container, element_type >::value )) + > + gsl_api gsl_constexpr gsl_explicit span( Container const & cont ) gsl_noexcept + : storage_( std17::data( cont ), std17::size( cont ) ) + { + } + template< class Container, gsl_CONFIG_SPAN_INDEX_TYPE MyExtent = Extent + // We *have* to use SFINAE with an NTTP arg here, otherwise the overload is ambiguous. + gsl_ENABLE_IF_NTTP_(( MyExtent == dynamic_extent && + std::is_const< element_type >::value && + detail::is_compatible_container< Container, element_type >::value )) + > + gsl_api gsl_constexpr span( Container const & cont ) gsl_noexcept + : storage_( std17::data( cont ), std17::size( cont ) ) + { + } +# else // gsl_BETWEEN( gsl_COMPILER_MSVC_VERSION, 1, 140 ) + template< class Container + gsl_ENABLE_IF_(( detail::is_compatible_container< Container, element_type >::value )) + > + gsl_api gsl_constexpr span( Container & cont ) gsl_noexcept + : storage_( std17::data( cont ), std17::size( cont ) ) + { + } + template< class Container, gsl_CONFIG_SPAN_INDEX_TYPE MyExtent = Extent + gsl_ENABLE_IF_(( std::is_const< element_type >::value && + detail::is_compatible_container< Container, element_type >::value )) + > + gsl_api gsl_constexpr span( Container const & cont ) gsl_noexcept + : storage_( std17::data( cont ), std17::size( cont ) ) + { + } +# endif // ! gsl_BETWEEN( gsl_COMPILER_MSVC_VERSION, 1, 140 ) +#elif gsl_HAVE( UNCONSTRAINED_SPAN_CONTAINER_CTOR ) + template< class Container > + gsl_constexpr span( Container & cont ) + : storage_( cont.size() == 0 ? gsl_nullptr : gsl_ADDRESSOF( cont[0] ), cont.size() ) + { + } + template< class Container > + gsl_constexpr span( Container const & cont ) + : storage_( cont.size() == 0 ? gsl_nullptr : gsl_ADDRESSOF( cont[0] ), cont.size() ) + { + } +#endif + +#if gsl_FEATURE_TO_STD( WITH_CONTAINER ) + template< class Container > + gsl_constexpr span( with_container_t, Container & cont ) + : storage_( cont.size() == 0 ? gsl_nullptr : gsl_ADDRESSOF( cont[0] ), cont.size() ) + { + } + template< class Container > + gsl_constexpr span( with_container_t, Container const & cont ) + : storage_( cont.size() == 0 ? gsl_nullptr : gsl_ADDRESSOF( cont[0] ), cont.size() ) + { + } +#endif + +#if gsl_HAVE( IS_DEFAULT ) && ! gsl_BETWEEN( gsl_COMPILER_GNUC_VERSION, 430, 600) + gsl_constexpr span( span && ) gsl_noexcept = default; + gsl_constexpr span( span const & ) = default; +#else + gsl_api gsl_constexpr span( span const & other ) + : storage_( other.storage_ ) + { + } +#endif + +#if gsl_HAVE( IS_DEFAULT ) + gsl_constexpr14 span & operator=( span && ) gsl_noexcept = default; + gsl_constexpr14 span & operator=( span const & ) gsl_noexcept = default; +#else + gsl_constexpr14 span & operator=( span const & other ) gsl_noexcept + { + storage_ = other.storage_; + return *this; + } +#endif + +#if gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) && ! gsl_BETWEEN( gsl_COMPILER_MSVC_VERSION, 1, 140 ) + template< + class OtherElementType, gsl_CONFIG_SPAN_INDEX_TYPE OtherExtent, gsl_CONFIG_SPAN_INDEX_TYPE MyExtent = Extent + // We *have* to use SFINAE with an NTTP arg here, otherwise the overload is ambiguous. + gsl_ENABLE_IF_NTTP_(( ( MyExtent == dynamic_extent || MyExtent == OtherExtent ) && + detail::is_allowed_element_type_conversion< OtherElementType, element_type >::value )) + > + gsl_api gsl_constexpr span( span< OtherElementType, OtherExtent > const & other ) gsl_noexcept + : storage_( other.data(), detail::extent_type< OtherExtent >( other.size() ) ) + { + } + template< + class OtherElementType, gsl_CONFIG_SPAN_INDEX_TYPE OtherExtent, gsl_CONFIG_SPAN_INDEX_TYPE MyExtent = Extent + // We *have* to use SFINAE with an NTTP arg here, otherwise the overload is ambiguous. + gsl_ENABLE_IF_NTTP_(( MyExtent != dynamic_extent && OtherExtent == dynamic_extent && + detail::is_allowed_element_type_conversion< OtherElementType, element_type >::value )) + > + gsl_api gsl_constexpr gsl_explicit span( span< OtherElementType, OtherExtent > const & other ) gsl_noexcept + : storage_( other.data(), detail::extent_type< OtherExtent >( other.size() ) ) + { + } +#else // !( gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) && ! gsl_BETWEEN( gsl_COMPILER_MSVC_VERSION, 1, 140 ) ) + template< class OtherElementType, gsl_CONFIG_SPAN_INDEX_TYPE OtherExtent > + gsl_api gsl_constexpr14 span( span< OtherElementType, OtherExtent > const & other ) + : storage_( other.data(), detail::extent_type< OtherExtent >( other.size() ) ) + { + gsl_STATIC_ASSERT_( + Extent == dynamic_extent || OtherExtent == dynamic_extent || Extent == OtherExtent, + "attempting copy-construction from incompatible span" ); + gsl_Expects( Extent == dynamic_extent || other.size() == Extent ); + } +#endif // gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) && ! gsl_BETWEEN( gsl_COMPILER_MSVC_VERSION, 1, 140 ) + + // [span.sub], span subviews + + template< gsl_CONFIG_SPAN_INDEX_TYPE Count > + gsl_NODISCARD gsl_api gsl_constexpr14 span< element_type, Count > + first() const + { + gsl_STATIC_ASSERT_( + Extent == dynamic_extent || Count <= Extent, + "first() cannot extract more elements from a span than it contains" ); + gsl_Expects( static_cast<std::size_t>( Count ) <= static_cast<std::size_t>( size() ) ); + return span< element_type, Count >( data(), Count ); + } + + template < gsl_CONFIG_SPAN_INDEX_TYPE Count > + gsl_SUPPRESS_MSGSL_WARNING(bounds.1) + gsl_NODISCARD gsl_api gsl_constexpr14 span< element_type, Count > + last() const + { + gsl_STATIC_ASSERT_( + Extent == dynamic_extent || Count <= Extent, + "last() cannot extract more elements from a span than it contains" ); + gsl_Expects( static_cast<std::size_t>( Count ) <= static_cast<std::size_t>( size() ) ); + return span< element_type, Count >( data() + ( size() - Count ), Count ); + } + + template < gsl_CONFIG_SPAN_INDEX_TYPE Offset, gsl_CONFIG_SPAN_INDEX_TYPE Count > + gsl_SUPPRESS_MSGSL_WARNING(bounds.1) + gsl_NODISCARD gsl_api gsl_constexpr14 typename detail::calculate_subspan_type< T, Extent, Offset, Count >::type + subspan() const + { + gsl_STATIC_ASSERT_( + Extent == dynamic_extent || ( Extent >= Offset && ( Count == dynamic_extent || + Count <= Extent - Offset ) ), + "subspan() cannot extract more elements from a span than it contains."); + gsl_Expects( static_cast<std::size_t>( size() ) >= static_cast<std::size_t>( Offset ) && + ( Count == dynamic_extent || static_cast<std::size_t>( Count ) <= static_cast<std::size_t>( size() ) - static_cast<std::size_t>( Offset ) ) ); + typedef typename detail::calculate_subspan_type< T, Extent, Offset, Count >::type type; + return type( data() + Offset, Count == dynamic_extent ? size() - Offset : Count ); + } + template < gsl_CONFIG_SPAN_INDEX_TYPE Offset > + gsl_SUPPRESS_MSGSL_WARNING(bounds.1) + gsl_NODISCARD gsl_api gsl_constexpr14 typename detail::calculate_subspan_type< T, Extent, Offset, dynamic_extent >::type + subspan() const + { + gsl_STATIC_ASSERT_( + Extent == dynamic_extent || Extent >= Offset, + "subspan() cannot extract more elements from a span than it contains."); + gsl_Expects( static_cast<std::size_t>( size() ) >= static_cast<std::size_t>( Offset ) ); + typedef typename detail::calculate_subspan_type< T, Extent, Offset, dynamic_extent >::type type; + return type( data() + Offset, size() - Offset ); + } + + gsl_NODISCARD gsl_api gsl_constexpr14 span< element_type, dynamic_extent > + first( size_type count ) const + { + gsl_Expects( static_cast<std::size_t>( count ) <= static_cast<std::size_t>( size() ) ); + return span< element_type, dynamic_extent >( data(), count ); + } + gsl_NODISCARD gsl_api gsl_constexpr14 span< element_type, dynamic_extent > + last( size_type count ) const + { + gsl_Expects( static_cast<std::size_t>( count ) <= static_cast<std::size_t>( size() ) ); + return make_subspan( size() - count, dynamic_extent, subspan_selector< Extent >() ); + } + + gsl_NODISCARD gsl_api gsl_constexpr14 span<element_type, dynamic_extent> + subspan(size_type offset, size_type count = dynamic_extent) const + { + return make_subspan(offset, count, subspan_selector< Extent >() ); + } + + // [span.obs], span observers + + gsl_NODISCARD gsl_api gsl_constexpr size_type + size() const gsl_noexcept + { + return storage_.size(); + } + gsl_NODISCARD gsl_api gsl_constexpr std::ptrdiff_t + ssize() const gsl_noexcept + { + return gsl_lite::narrow_cast< std::ptrdiff_t >( storage_.size() ); + } + + gsl_NODISCARD gsl_api gsl_constexpr size_type + size_bytes() const gsl_noexcept + { + return size() * sizeof(element_type); + } + + gsl_NODISCARD gsl_api gsl_constexpr bool + empty() const gsl_noexcept + { + return size() == 0; + } + + // [span.elem], span element access + + gsl_SUPPRESS_MSGSL_WARNING(bounds.1) + gsl_NODISCARD gsl_api gsl_constexpr14 reference + operator[](size_type idx) const + { + gsl_Expects( static_cast<std::size_t>( idx ) < static_cast<std::size_t>( size() ) ); + return storage_.data()[ idx ]; + } + + gsl_NODISCARD gsl_api gsl_constexpr14 + reference front() const + { + gsl_Expects( size() > 0 ); + return storage_.data()[ 0 ]; + } + + gsl_NODISCARD gsl_api gsl_constexpr14 + reference back() const + { + gsl_Expects( size() > 0 ); + return storage_.data()[ size() - 1 ]; + } + + gsl_NODISCARD gsl_api gsl_constexpr pointer + data() const gsl_noexcept + { + return storage_.data(); + } + + // [span.iter], span iterator support + + gsl_NODISCARD gsl_api gsl_constexpr14 iterator + begin() const gsl_noexcept + { + const pointer data = storage_.data(); + gsl_SUPPRESS_MSGSL_WARNING(bounds.1) + return iterator( data, data + size(), data ); + } + gsl_NODISCARD gsl_api gsl_constexpr14 iterator + end() const gsl_noexcept + { + const pointer data = storage_.data(); + gsl_SUPPRESS_MSGSL_WARNING(bounds.1) + const pointer endData = data + storage_.size(); + return iterator( data, endData, endData ); + } + gsl_NODISCARD gsl_api gsl_constexpr14 const_iterator + cbegin() const gsl_noexcept + { + const pointer data = storage_.data(); + gsl_SUPPRESS_MSGSL_WARNING(bounds.1) + return const_iterator( data, data + size(), data ); + } + gsl_NODISCARD gsl_api gsl_constexpr14 const_iterator + cend() const gsl_noexcept + { + const pointer data = storage_.data(); + gsl_SUPPRESS_MSGSL_WARNING(bounds.1) + const pointer endData = data + storage_.size(); + return const_iterator( data, endData, endData ); + } + + gsl_NODISCARD gsl_api gsl_constexpr14 reverse_iterator + rbegin() const gsl_noexcept + { + return reverse_iterator( end() ); + } + gsl_NODISCARD gsl_api gsl_constexpr14 reverse_iterator + rend() const gsl_noexcept + { + return reverse_iterator( begin() ); + } + + gsl_NODISCARD gsl_api gsl_constexpr14 const_reverse_iterator + crbegin() const gsl_noexcept + { + return const_reverse_iterator( cend() ); + } + gsl_NODISCARD gsl_api gsl_constexpr14 const_reverse_iterator + crend() const gsl_noexcept + { + return const_reverse_iterator( cbegin() ); + } + + gsl_constexpr14 void + swap( span & other ) gsl_noexcept + { + std::swap( storage_, other.storage_ ); + } + +#if ! gsl_DEPRECATE_TO_LEVEL( 9 ) + template< class U > + gsl_DEPRECATED_MSG("as_span() member function is unsafe") + gsl_NODISCARD gsl_api typename detail::calculate_recast_span_type< element_type, U, Extent >::type + as_span() const + { + gsl_Expects( ( this->size_bytes() % sizeof( U ) ) == 0 ); + typedef typename detail::calculate_recast_span_type< element_type, U, Extent >::type type; + return type( reinterpret_cast<U *>( data() ), size_bytes() / sizeof( U ) ); // NOLINT + } +#endif // ! gsl_DEPRECATE_TO_LEVEL( 9 ) + +#ifdef _MSC_VER + // Tell MSVC how to unwrap spans in range-based-for + gsl_api gsl_constexpr pointer _Unchecked_begin() const gsl_noexcept { return data(); } + gsl_api gsl_constexpr pointer _Unchecked_end() const gsl_noexcept + { + gsl_SUPPRESS_MSGSL_WARNING(bounds.1) + return data() + size(); + } +#endif // _MSC_VER + +private: + // Needed to remove unnecessary null check in subspans + struct known_not_null + { + pointer p; + + gsl_api gsl_constexpr known_not_null(pointer _p) gsl_noexcept + : p( _p ) + { + } + }; + + // this implementation detail class lets us take advantage of the + // empty base class optimization to pay for only storage of a single + // pointer in the case of fixed-size spans + template< class ExtentType > + class storage_type : public ExtentType + { + public: + gsl_api gsl_constexpr storage_type( detail::extent_type< 0 > ext ) + : ExtentType( ext ), data_( gsl_nullptr ) + { + } + + // known_not_null parameter is needed to remove unnecessary null check + // in subspans and constructors from arrays + template< class OtherExtentType > + gsl_api gsl_constexpr storage_type( known_not_null data, OtherExtentType ext ) + : ExtentType( ext ), data_( data.p ) + { + } + + template< class OtherExtentType > + gsl_api gsl_constexpr14 storage_type( pointer data, OtherExtentType ext ) + : ExtentType( ext ), data_( data ) + { + gsl_Expects( data || ExtentType::size() == 0 ); + } + + gsl_api gsl_constexpr pointer data() const gsl_noexcept { return data_; } + + private: + pointer data_; + }; + + storage_type< detail::extent_type< Extent > > storage_; + + // The rest is needed to remove unnecessary null check + // in subspans and constructors from arrays + gsl_api gsl_constexpr span( known_not_null ptr, size_type count ) gsl_noexcept + : storage_(ptr, count) + { + } + + template< gsl_CONFIG_SPAN_INDEX_TYPE CallerExtent > + class subspan_selector + { + }; + + template < gsl_CONFIG_SPAN_INDEX_TYPE CallerExtent > + gsl_api gsl_constexpr14 span< element_type, dynamic_extent > + make_subspan( size_type offset, size_type count, subspan_selector< CallerExtent > ) const + { + span< element_type, dynamic_extent > const tmp( *this ); + return tmp.subspan( offset, count ); + } + + gsl_SUPPRESS_MSGSL_WARNING(bounds.1) + gsl_api gsl_constexpr14 span< element_type, dynamic_extent > + make_subspan( size_type offset, size_type count, subspan_selector< dynamic_extent > ) const + { + gsl_Expects( static_cast<std::size_t>( size() ) >= static_cast<std::size_t>( offset ) ); + + if ( count == dynamic_extent ) + { + return span< element_type, dynamic_extent >( known_not_null( data() + offset ), size() - offset ); + } + + gsl_Expects( static_cast<std::size_t>( size() ) - static_cast<std::size_t>( offset ) >= static_cast<std::size_t>( count ) ); + return span< element_type, dynamic_extent >( known_not_null( data() + offset ), count ); + } +}; + +// class template argument deduction guides: + +#if gsl_HAVE( DEDUCTION_GUIDES ) // gsl_CPP17_OR_GREATER + +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( std::array<Type, Size> const & ) -> span< Type const, 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< Container const & >().data()) > > +span( Container const & ) -> span< Element >; + +#endif // gsl_HAVE( DEDUCTION_GUIDES ) + +#if ! gsl_CPP17_OR_GREATER +# if defined( __clang__ ) && defined( _MSC_VER ) +# 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 ) +template< class T, gsl_CONFIG_SPAN_INDEX_TYPE Extent > +gsl_constexpr const typename span< T, Extent >::size_type span< T, Extent >::extent; +# if defined( __clang__ ) && defined( _MSC_VER ) +# pragma clang diagnostic pop +# endif // defined( __clang__ ) && defined( _MSC_VER ) +#endif // ! gsl_CPP17_OR_GREATER + +#if gsl_COMPILER_MSVC_VER +# pragma warning( pop ) +#endif // gsl_COMPILER_MSVC_VER + +#if defined( __GNUC__ ) && __GNUC__ > 6 +# pragma GCC diagnostic pop +#endif // defined( __GNUC__ ) && __GNUC__ > 6 + +#if defined( __clang__ ) +# if __has_warning( "-Wunsafe-buffer-usage" ) +# pragma clang diagnostic pop +# endif // __has_warning( "-Wunsafe-buffer-usage" ) +#endif // defined( __clang__ ) + +// 26.7.3.7 Comparison operators [span.comparison] + +#if gsl_CONFIG( ALLOWS_SPAN_COMPARISON ) +# if gsl_CONFIG( ALLOWS_NONSTRICT_SPAN_COMPARISON ) + +template< class T, class U, gsl_CONFIG_SPAN_INDEX_TYPE LExtent, gsl_CONFIG_SPAN_INDEX_TYPE RExtent > +gsl_SUPPRESS_MSGSL_WARNING(stl.1) +gsl_NODISCARD inline gsl_constexpr bool operator==( span<T, LExtent> const & l, span<U, RExtent> const & r ) +{ + gsl_STATIC_ASSERT_( LExtent == RExtent || LExtent == dynamic_extent || RExtent == dynamic_extent, "comparing spans of mismatching sizes" ); + return l.size() == r.size() + && ( l.data() == r.data() || detail::equal( l.begin(), l.end(), r.begin() ) ); +} + +template< class T, class U, gsl_CONFIG_SPAN_INDEX_TYPE LExtent, gsl_CONFIG_SPAN_INDEX_TYPE RExtent > +gsl_SUPPRESS_MSGSL_WARNING(stl.1) +gsl_NODISCARD inline gsl_constexpr bool operator< ( span<T, LExtent> const & l, span<U, RExtent> const & r ) +{ + return detail::lexicographical_compare( l.begin(), l.end(), r.begin(), r.end() ); +} + +# else // a.k.a. !gsl_CONFIG( ALLOWS_NONSTRICT_SPAN_COMPARISON ) + +template< class T, gsl_CONFIG_SPAN_INDEX_TYPE LExtent, gsl_CONFIG_SPAN_INDEX_TYPE RExtent > +gsl_SUPPRESS_MSGSL_WARNING(stl.1) +gsl_NODISCARD inline gsl_constexpr bool operator==( span<T, LExtent> const & l, span<T, RExtent> const & r ) +{ + gsl_STATIC_ASSERT_( LExtent == RExtent || LExtent == dynamic_extent || RExtent == dynamic_extent, "comparing spans of mismatching sizes" ); + return l.size() == r.size() + && ( l.data() == r.data() || detail::equal( l.begin(), l.end(), r.begin() ) ); +} + +template< class T, gsl_CONFIG_SPAN_INDEX_TYPE LExtent, gsl_CONFIG_SPAN_INDEX_TYPE RExtent > +gsl_SUPPRESS_MSGSL_WARNING(stl.1) +gsl_NODISCARD inline gsl_constexpr bool operator< ( span<T, LExtent> const & l, span<T, RExtent> const & r ) +{ + return detail::lexicographical_compare( l.begin(), l.end(), r.begin(), r.end() ); +} +# endif // gsl_CONFIG( ALLOWS_NONSTRICT_SPAN_COMPARISON ) + +template< class T, class U, gsl_CONFIG_SPAN_INDEX_TYPE LExtent, gsl_CONFIG_SPAN_INDEX_TYPE RExtent > +gsl_NODISCARD inline gsl_constexpr bool +operator!=( span<T, LExtent> const & l, span<U, RExtent> const & r ) +{ + return !( l == r ); +} + +template< class T, class U, gsl_CONFIG_SPAN_INDEX_TYPE LExtent, gsl_CONFIG_SPAN_INDEX_TYPE RExtent > +gsl_NODISCARD inline gsl_constexpr bool +operator<=( span<T, LExtent> const & l, span<U, RExtent> const & r ) +{ + return !( r < l ); +} + +template< class T, class U, gsl_CONFIG_SPAN_INDEX_TYPE LExtent, gsl_CONFIG_SPAN_INDEX_TYPE RExtent > +gsl_NODISCARD inline gsl_constexpr bool +operator>( span<T, LExtent> const & l, span<U, RExtent> const & r ) +{ + return ( r < l ); +} + +template< class T, class U, gsl_CONFIG_SPAN_INDEX_TYPE LExtent, gsl_CONFIG_SPAN_INDEX_TYPE RExtent > +gsl_NODISCARD inline gsl_constexpr bool +operator>=( span<T, LExtent> const & l, span<U, RExtent> const & r ) +{ + return !( l < r ); +} +#endif // gsl_CONFIG( ALLOWS_SPAN_COMPARISON ) + +// span algorithms + +template< class T, gsl_CONFIG_SPAN_INDEX_TYPE Extent > +gsl_NODISCARD gsl_api inline gsl_constexpr std::size_t +size( span<T, Extent> const & spn ) +{ + return static_cast<std::size_t>( spn.size() ); +} + +template< class T, gsl_CONFIG_SPAN_INDEX_TYPE Extent > +gsl_NODISCARD gsl_api inline gsl_constexpr std::ptrdiff_t +ssize( span<T, Extent> const & spn ) +{ + return spn.ssize(); +} + +namespace detail { + +template< class II, class N, class OI > +gsl_api gsl_constexpr14 inline OI copy_n( II first, N count, OI result ) +{ + if ( count > 0 ) + { + *result++ = *first; + for ( N i = 1; i < count; ++i ) + { + *result++ = *++first; + } + } + return result; +} +} + +template< class T, class U, gsl_CONFIG_SPAN_INDEX_TYPE LExtent, gsl_CONFIG_SPAN_INDEX_TYPE RExtent > +gsl_api gsl_constexpr14 inline void copy( span<T, LExtent> src, span<U, RExtent> dest ) +{ +#if gsl_CPP14_OR_GREATER // gsl_HAVE( TYPE_TRAITS ) (circumvent Travis clang 3.4) + static_assert( std::is_assignable<U &, T const &>::value, "Cannot assign elements of source span to elements of destination span" ); +#endif + gsl_STATIC_ASSERT_( RExtent >= LExtent || LExtent == dynamic_extent || RExtent == dynamic_extent ,"incompatible span extents" ); + gsl_Expects( dest.size() >= src.size() ); + detail::copy_n( src.data(), src.size(), dest.data() ); +} + +#if gsl_FEATURE( BYTE ) +// span creator functions (see ctors) + +template< class T, gsl_CONFIG_SPAN_INDEX_TYPE Extent > +gsl_NODISCARD gsl_api inline span< const byte > +as_bytes( span< T, Extent > spn ) gsl_noexcept +{ + return span< const byte >( reinterpret_cast<const byte *>( spn.data() ), spn.size_bytes() ); // NOLINT +} + +template< class T, gsl_CONFIG_SPAN_INDEX_TYPE Extent > +gsl_NODISCARD gsl_api inline span< byte > +as_writable_bytes( span< T, Extent > spn ) gsl_noexcept +{ + return span< byte >( reinterpret_cast<byte *>( spn.data() ), spn.size_bytes() ); // NOLINT +} +#endif // gsl_FEATURE( BYTE ) + +#if gsl_FEATURE_TO_STD( MAKE_SPAN ) + +template< class T > +gsl_NODISCARD gsl_api inline gsl_constexpr span<T> +make_span( T * ptr, typename span<T>::index_type count ) +{ + return span<T>( ptr, count ); +} + +template< class T > +gsl_NODISCARD gsl_api inline gsl_constexpr span<T> +make_span( T * first, T * last ) +{ + return span<T>( first, last ); +} + +template< class T, std::size_t N > +gsl_NODISCARD inline gsl_constexpr span<T, static_cast<gsl_CONFIG_SPAN_INDEX_TYPE>( N )> +make_span( T (&arr)[N] ) +{ + return span<T, static_cast<gsl_CONFIG_SPAN_INDEX_TYPE>( N )>( arr ); +} + +# if gsl_HAVE( ARRAY ) + +template< class T, std::size_t N > +gsl_NODISCARD inline gsl_constexpr span<T, static_cast<gsl_CONFIG_SPAN_INDEX_TYPE>( N )> +make_span( std::array<T, N> & arr ) +{ + return span<T, static_cast<gsl_CONFIG_SPAN_INDEX_TYPE>( N )>( arr ); +} + +template< class T, std::size_t N > +gsl_NODISCARD inline gsl_constexpr span<const T, static_cast<gsl_CONFIG_SPAN_INDEX_TYPE>( N )> +make_span( std::array<T, N> const & arr ) +{ + return span<const T, static_cast<gsl_CONFIG_SPAN_INDEX_TYPE>( N )>( arr ); +} +# endif + +# if gsl_HAVE( CONSTRAINED_SPAN_CONTAINER_CTOR ) && gsl_HAVE( AUTO ) + +template< class Container, class EP = decltype( std17::data(std::declval<Container&>())) > +gsl_NODISCARD inline gsl_constexpr auto +make_span( Container & cont ) -> span< typename std::remove_pointer<EP>::type > +{ + return span< typename std::remove_pointer<EP>::type >( cont ); +} + +template< class Container, class EP = decltype( std17::data(std::declval<Container&>())) > +gsl_NODISCARD inline gsl_constexpr auto +make_span( Container const & cont ) -> span< const typename std::remove_pointer<EP>::type > +{ + return span< const typename std::remove_pointer<EP>::type >( cont ); +} + +# else + +template< class T > +inline span<T> +make_span( std::vector<T> & cont ) +{ + return span<T>( cont.data(), cont.data() + cont.size() ); +} + +template< class T > +inline span<const T> +make_span( std::vector<T> const & cont ) +{ + return span<const T>( cont.data(), cont.data() + cont.size() ); +} + +# endif + +# if gsl_FEATURE_TO_STD( WITH_CONTAINER ) + +template< class Container > +gsl_NODISCARD inline gsl_constexpr span<typename Container::value_type> +make_span( with_container_t, Container & cont ) gsl_noexcept +{ + return span< typename Container::value_type >( with_container, cont ); +} + +template< class Container > +gsl_NODISCARD inline gsl_constexpr span<const typename Container::value_type> +make_span( with_container_t, Container const & cont ) gsl_noexcept +{ + return span< const typename Container::value_type >( with_container, cont ); +} + +# endif // gsl_FEATURE_TO_STD( WITH_CONTAINER ) +#endif // gsl_FEATURE_TO_STD( MAKE_SPAN ) + +#if gsl_FEATURE( BYTE ) && gsl_FEATURE_TO_STD( BYTE_SPAN ) + +template< class T > +gsl_NODISCARD gsl_api inline gsl_constexpr span<byte> +byte_span( T & t ) gsl_noexcept +{ + return span<byte>( reinterpret_cast<byte *>( &t ), sizeof(T) ); +} + +template< class T > +gsl_NODISCARD gsl_api inline gsl_constexpr span<const byte> +byte_span( T const & t ) gsl_noexcept +{ + return span<const byte>( reinterpret_cast<byte const *>( &t ), sizeof(T) ); +} + +#endif // gsl_FEATURE( BYTE ) && gsl_FEATURE_TO_STD( BYTE_SPAN ) + +#if gsl_FEATURE( STRING_SPAN ) +// +// basic_string_span: +// + +template< class T > +class basic_string_span; + +namespace detail { + +template< class T > +struct is_basic_string_span_oracle : std11::false_type {}; + +template< class T > +struct is_basic_string_span_oracle< basic_string_span<T> > : std11::true_type {}; + +template< class T > +struct is_basic_string_span : is_basic_string_span_oracle< typename std11::remove_cv<T>::type > {}; + +template< class T > +gsl_api inline gsl_constexpr14 std::size_t string_length( T * ptr, std::size_t max ) +{ + if ( ptr == gsl_nullptr || max <= 0 ) + return 0; + + std::size_t len = 0; + while ( len < max && ptr[len] ) // NOLINT + ++len; + + return len; +} + +} // namespace detail + +// +// basic_string_span<> - A view of contiguous characters, replace (*,len). +// +template< class T > +class basic_string_span +{ +public: + typedef T element_type; + typedef span<T> span_type; + + typedef typename span_type::size_type size_type; + typedef typename span_type::index_type index_type; + typedef typename span_type::difference_type difference_type; + + typedef typename span_type::pointer pointer ; + typedef typename span_type::reference reference ; + + typedef typename span_type::iterator iterator ; + typedef typename span_type::const_iterator const_iterator ; + typedef typename span_type::reverse_iterator reverse_iterator; + typedef typename span_type::const_reverse_iterator const_reverse_iterator; + + // construction: + +# if gsl_HAVE( IS_DEFAULT ) + gsl_constexpr basic_string_span() gsl_noexcept = default; +# else + gsl_api gsl_constexpr basic_string_span() gsl_noexcept {} +# endif + +# if gsl_HAVE( NULLPTR ) + gsl_api gsl_constexpr basic_string_span( std::nullptr_t ) gsl_noexcept + : span_( nullptr, static_cast<index_type>( 0 ) ) + {} +# endif + +# ifdef __CUDACC_RELAXED_CONSTEXPR__ + gsl_api +# endif // __CUDACC_RELAXED_CONSTEXPR__ +# if gsl_DEPRECATE_TO_LEVEL( 7 ) + gsl_DEPRECATED_MSG("basic_string_span<> is deprecated; use span<> instead") +# endif // gsl_DEPRECATE_TO_LEVEL( 7 ) + gsl_constexpr basic_string_span( pointer ptr ) + : span_( remove_z( ptr, (std::numeric_limits<index_type>::max)() ) ) + {} + +# if gsl_DEPRECATE_TO_LEVEL( 7 ) + gsl_DEPRECATED_MSG("basic_string_span<> is deprecated; use span<> instead") +# endif // gsl_DEPRECATE_TO_LEVEL( 7 ) + gsl_api gsl_constexpr basic_string_span( pointer ptr, index_type count ) + : span_( ptr, count ) + {} + +# if gsl_DEPRECATE_TO_LEVEL( 7 ) + gsl_DEPRECATED_MSG("basic_string_span<> is deprecated; use span<> instead") +# endif // gsl_DEPRECATE_TO_LEVEL( 7 ) + gsl_api gsl_constexpr basic_string_span( pointer firstElem, pointer lastElem ) + : span_( firstElem, lastElem ) + {} + + template< std::size_t N > +# if gsl_DEPRECATE_TO_LEVEL( 7 ) + gsl_DEPRECATED_MSG("basic_string_span<> is deprecated; use span<> instead") +# endif // gsl_DEPRECATE_TO_LEVEL( 7 ) + gsl_constexpr basic_string_span( element_type (&arr)[N] ) + : span_( remove_z( gsl_ADDRESSOF( arr[0] ), N ) ) + {} + +# if gsl_HAVE( ARRAY ) + + template< std::size_t N > +# if gsl_DEPRECATE_TO_LEVEL( 7 ) + gsl_DEPRECATED_MSG("basic_string_span<> is deprecated; use span<> instead") +# endif // gsl_DEPRECATE_TO_LEVEL( 7 ) + gsl_constexpr basic_string_span( std::array< typename std11::remove_const<element_type>::type, N> & arr ) + : span_( remove_z( arr ) ) + {} + + template< std::size_t N > +# if gsl_DEPRECATE_TO_LEVEL( 7 ) + gsl_DEPRECATED_MSG("basic_string_span<> is deprecated; use span<> instead") +# endif // gsl_DEPRECATE_TO_LEVEL( 7 ) + gsl_constexpr basic_string_span( std::array< typename std11::remove_const<element_type>::type, N> const & arr ) + : span_( remove_z( arr ) ) + {} + +# endif // gsl_HAVE( ARRAY ) + +# if gsl_HAVE( CONSTRAINED_SPAN_CONTAINER_CTOR ) + + // Exclude: array, [basic_string,] basic_string_span + + template< class Container + gsl_ENABLE_IF_(( + ! detail::is_std_array< Container >::value + && ! detail::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 + )) + > +# if gsl_DEPRECATE_TO_LEVEL( 7 ) + gsl_DEPRECATED_MSG("basic_string_span<> is deprecated; use span<> instead") +# endif // gsl_DEPRECATE_TO_LEVEL( 7 ) + gsl_constexpr basic_string_span( Container & cont ) + : span_( ( cont ) ) + {} + + // Exclude: array, [basic_string,] basic_string_span + + template< class Container + gsl_ENABLE_IF_(( + ! detail::is_std_array< Container >::value + && ! detail::is_basic_string_span< Container >::value + && std::is_convertible< typename Container::pointer, pointer >::value + && std::is_convertible< typename Container::pointer, decltype(std::declval<Container const &>().data()) >::value + )) + > +# if gsl_DEPRECATE_TO_LEVEL( 7 ) + gsl_DEPRECATED_MSG("basic_string_span<> is deprecated; use span<> instead") +# endif // gsl_DEPRECATE_TO_LEVEL( 7 ) + gsl_constexpr basic_string_span( Container const & cont ) + : span_( ( cont ) ) + {} + +# elif gsl_HAVE( UNCONSTRAINED_SPAN_CONTAINER_CTOR ) + + template< class Container > +# if gsl_DEPRECATE_TO_LEVEL( 7 ) + gsl_DEPRECATED_MSG("basic_string_span<> is deprecated; use span<> instead") +# endif // gsl_DEPRECATE_TO_LEVEL( 7 ) + gsl_constexpr basic_string_span( Container & cont ) + : span_( cont ) + {} + + template< class Container > +# if gsl_DEPRECATE_TO_LEVEL( 7 ) + gsl_DEPRECATED_MSG("basic_string_span<> is deprecated; use span<> instead") +# endif // gsl_DEPRECATE_TO_LEVEL( 7 ) + gsl_constexpr basic_string_span( Container const & cont ) + : span_( cont ) + {} + +# else + + template< class U, gsl_CONFIG_SPAN_INDEX_TYPE Extent > +# if gsl_DEPRECATE_TO_LEVEL( 7 ) + gsl_DEPRECATED_MSG("basic_string_span<> is deprecated; use span<> instead") +# endif // gsl_DEPRECATE_TO_LEVEL( 7 ) + gsl_api gsl_constexpr basic_string_span( span< U, Extent > const & rhs ) + : span_( rhs ) + {} + +# endif + +# if gsl_FEATURE_TO_STD( WITH_CONTAINER ) + + template< class Container > +# if gsl_DEPRECATE_TO_LEVEL( 7 ) + gsl_DEPRECATED_MSG("basic_string_span<> is deprecated; use span<> instead") +# endif // gsl_DEPRECATE_TO_LEVEL( 7 ) + gsl_constexpr basic_string_span( with_container_t, Container & cont ) + : span_( with_container, cont ) + {} +# endif + +# if gsl_HAVE( IS_DEFAULT ) +# if gsl_BETWEEN( gsl_COMPILER_GNUC_VERSION, 440, 600 ) + gsl_constexpr basic_string_span( basic_string_span const & ) = default; + + gsl_constexpr basic_string_span( basic_string_span && ) = default; +# else + gsl_constexpr basic_string_span( basic_string_span const & ) gsl_noexcept = default; + + gsl_constexpr basic_string_span( basic_string_span && ) gsl_noexcept = default; +# endif +# endif + + template< class U + gsl_ENABLE_IF_(( std::is_convertible<typename basic_string_span<U>::pointer, pointer>::value )) + > +# if gsl_DEPRECATE_TO_LEVEL( 7 ) + gsl_DEPRECATED_MSG("basic_string_span<> is deprecated; use span<> instead") +# endif // gsl_DEPRECATE_TO_LEVEL( 7 ) + gsl_api gsl_constexpr basic_string_span( basic_string_span<U> const & rhs ) + : span_( reinterpret_cast<pointer>( rhs.data() ), rhs.length() ) // NOLINT + {} + +# if gsl_STDLIB_CPP11_120 + template< class U + gsl_ENABLE_IF_(( std::is_convertible<typename basic_string_span<U>::pointer, pointer>::value )) + > +# if gsl_DEPRECATE_TO_LEVEL( 7 ) + gsl_DEPRECATED_MSG("basic_string_span<> is deprecated; use span<> instead") +# endif // gsl_DEPRECATE_TO_LEVEL( 7 ) + gsl_api gsl_constexpr basic_string_span( basic_string_span<U> && rhs ) + : span_( reinterpret_cast<pointer>( rhs.data() ), rhs.length() ) // NOLINT + {} +# endif // gsl_STDLIB_CPP11_120 + + template< class CharTraits, class Allocator > +# if gsl_DEPRECATE_TO_LEVEL( 7 ) + gsl_DEPRECATED_MSG("basic_string_span<> is deprecated; use span<> instead") +# endif // gsl_DEPRECATE_TO_LEVEL( 7 ) + gsl_constexpr basic_string_span( + std::basic_string< typename std11::remove_const<element_type>::type, CharTraits, Allocator > & str ) + : span_( gsl_ADDRESSOF( str[0] ), str.length() ) + {} + + template< class CharTraits, class Allocator > +# if gsl_DEPRECATE_TO_LEVEL( 7 ) + gsl_DEPRECATED_MSG("basic_string_span<> is deprecated; use span<> instead") +# endif // gsl_DEPRECATE_TO_LEVEL( 7 ) + gsl_constexpr basic_string_span( + std::basic_string< typename std11::remove_const<element_type>::type, CharTraits, Allocator > const & str ) + : span_( gsl_ADDRESSOF( str[0] ), str.length() ) + {} + + // assignment: + +# if gsl_HAVE( IS_DEFAULT ) + gsl_constexpr14 basic_string_span & operator=( basic_string_span const & ) gsl_noexcept = default; + + gsl_constexpr14 basic_string_span & operator=( basic_string_span && ) gsl_noexcept = default; +# endif + + // sub span: + + /*gsl_api*/ // currently disabled due to an apparent NVCC bug + gsl_NODISCARD gsl_constexpr14 basic_string_span + first( index_type count ) const + { + return span_.first( count ); + } + + /*gsl_api*/ // currently disabled due to an apparent NVCC bug + gsl_NODISCARD gsl_constexpr14 basic_string_span + last( index_type count ) const + { + return span_.last( count ); + } + + /*gsl_api*/ // currently disabled due to an apparent NVCC bug + gsl_NODISCARD gsl_constexpr14 basic_string_span + subspan( index_type offset ) const + { + return span_.subspan( offset ); + } + + /*gsl_api*/ // currently disabled due to an apparent NVCC bug + gsl_NODISCARD gsl_constexpr14 basic_string_span + subspan( index_type offset, index_type count ) const + { + return span_.subspan( offset, count ); + } + + // observers: + + gsl_NODISCARD gsl_api gsl_constexpr index_type + length() const gsl_noexcept + { + return span_.size(); + } + + gsl_NODISCARD gsl_api gsl_constexpr index_type + size() const gsl_noexcept + { + return span_.size(); + } + + gsl_NODISCARD gsl_api gsl_constexpr index_type + length_bytes() const gsl_noexcept + { + return span_.size_bytes(); + } + + gsl_NODISCARD gsl_api gsl_constexpr index_type + size_bytes() const gsl_noexcept + { + return span_.size_bytes(); + } + + gsl_NODISCARD gsl_api gsl_constexpr bool + empty() const gsl_noexcept + { + return size() == 0; + } + + gsl_NODISCARD gsl_api gsl_constexpr14 reference + operator[]( index_type idx ) const + { + return span_[idx]; + } + + gsl_NODISCARD gsl_api gsl_constexpr14 reference + front() const + { + return span_.front(); + } + + gsl_NODISCARD gsl_api gsl_constexpr14 reference + back() const + { + return span_.back(); + } + + gsl_NODISCARD gsl_api gsl_constexpr pointer + data() const gsl_noexcept + { + return span_.data(); + } + + gsl_NODISCARD gsl_api gsl_constexpr iterator + begin() const gsl_noexcept + { + return span_.begin(); + } + + gsl_NODISCARD gsl_api gsl_constexpr iterator + end() const gsl_noexcept + { + return span_.end(); + } + + gsl_NODISCARD gsl_constexpr17 reverse_iterator + rbegin() const gsl_noexcept + { + return span_.rbegin(); + } + + gsl_NODISCARD gsl_constexpr17 reverse_iterator + rend() const gsl_noexcept + { + return span_.rend(); + } + + // const version not in p0123r2: + + gsl_NODISCARD gsl_api gsl_constexpr const_iterator + cbegin() const gsl_noexcept + { + return span_.cbegin(); + } + + gsl_NODISCARD gsl_api gsl_constexpr const_iterator + cend() const gsl_noexcept + { + return span_.cend(); + } + + gsl_NODISCARD gsl_constexpr17 const_reverse_iterator + crbegin() const gsl_noexcept + { + return span_.crbegin(); + } + + gsl_NODISCARD gsl_constexpr17 const_reverse_iterator + crend() const gsl_noexcept + { + return span_.crend(); + } + +private: + gsl_api static gsl_constexpr14 span_type remove_z( pointer sz, std::size_t max ) + { + return span_type( sz, detail::string_length( sz, max ) ); + } + +# if gsl_HAVE( ARRAY ) + template< size_t N > + gsl_NODISCARD static gsl_constexpr14 span_type + remove_z( std::array<typename std11::remove_const<element_type>::type, N> & arr ) + { + return remove_z( gsl_ADDRESSOF( arr[0] ), gsl_lite::narrow_cast< std::size_t >( N ) ); + } + + template< size_t N > + gsl_NODISCARD static gsl_constexpr14 span_type + remove_z( std::array<typename std11::remove_const<element_type>::type, N> const & arr ) + { + return remove_z( gsl_ADDRESSOF( arr[0] ), gsl_lite::narrow_cast< std::size_t >( N ) ); + } +# endif + +private: + span_type span_; +}; + +// basic_string_span comparison functions: + +# if gsl_CONFIG( ALLOWS_NONSTRICT_SPAN_COMPARISON ) + +template< class T, class U > +gsl_SUPPRESS_MSGSL_WARNING(stl.1) +gsl_NODISCARD inline gsl_constexpr14 bool +operator==( basic_string_span<T> const & l, U const & u ) gsl_noexcept +{ + const basic_string_span< typename std11::add_const<T>::type > r( u ); + + return l.size() == r.size() + && detail::equal( l.begin(), l.end(), r.begin() ); +} + +template< class T, class U > +gsl_SUPPRESS_MSGSL_WARNING(stl.1) +gsl_NODISCARD inline gsl_constexpr14 bool +operator<( basic_string_span<T> const & l, U const & u ) gsl_noexcept +{ + const basic_string_span< typename std11::add_const<T>::type > r( u ); + + return detail::lexicographical_compare( l.begin(), l.end(), r.begin(), r.end() ); +} + +# if gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) + +template< class T, class U + gsl_ENABLE_IF_(( !detail::is_basic_string_span<U>::value )) +> +gsl_SUPPRESS_MSGSL_WARNING(stl.1) +gsl_NODISCARD inline gsl_constexpr14 bool +operator==( U const & u, basic_string_span<T> const & r ) gsl_noexcept +{ + const basic_string_span< typename std11::add_const<T>::type > l( u ); + + return l.size() == r.size() + && detail::equal( l.begin(), l.end(), r.begin() ); +} + +template< class T, class U + gsl_ENABLE_IF_(( !detail::is_basic_string_span<U>::value )) +> +gsl_SUPPRESS_MSGSL_WARNING(stl.1) +gsl_NODISCARD inline gsl_constexpr14 bool +operator<( U const & u, basic_string_span<T> const & r ) gsl_noexcept +{ + const basic_string_span< typename std11::add_const<T>::type > l( u ); + + return detail::lexicographical_compare( l.begin(), l.end(), r.begin(), r.end() ); +} +# endif + +# else // ! gsl_CONFIG( ALLOWS_NONSTRICT_SPAN_COMPARISON ) + +template< class T > +gsl_SUPPRESS_MSGSL_WARNING(stl.1) +gsl_NODISCARD inline gsl_constexpr14 bool +operator==( basic_string_span<T> const & l, basic_string_span<T> const & r ) gsl_noexcept +{ + return l.size() == r.size() + && detail::equal( l.begin(), l.end(), r.begin() ); +} + +template< class T > +gsl_SUPPRESS_MSGSL_WARNING(stl.1) +gsl_NODISCARD inline gsl_constexpr14 bool +operator<( basic_string_span<T> const & l, basic_string_span<T> const & r ) gsl_noexcept +{ + return detail::lexicographical_compare( l.begin(), l.end(), r.begin(), r.end() ); +} + +# endif // gsl_CONFIG( ALLOWS_NONSTRICT_SPAN_COMPARISON ) + +template< class T, class U > +gsl_NODISCARD inline gsl_constexpr14 bool +operator!=( basic_string_span<T> const & l, U const & r ) gsl_noexcept +{ + return !( l == r ); +} + +template< class T, class U > +gsl_NODISCARD inline gsl_constexpr14 bool +operator<=( basic_string_span<T> const & l, U const & r ) gsl_noexcept +{ +# if gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) || ! gsl_CONFIG( ALLOWS_NONSTRICT_SPAN_COMPARISON ) + return !( r < l ); +# else + basic_string_span< typename std11::add_const<T>::type > rr( r ); + return !( rr < l ); +# endif +} + +template< class T, class U > +gsl_NODISCARD inline gsl_constexpr14 bool +operator>( basic_string_span<T> const & l, U const & r ) gsl_noexcept +{ +# if gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) || ! gsl_CONFIG( ALLOWS_NONSTRICT_SPAN_COMPARISON ) + return ( r < l ); +# else + basic_string_span< typename std11::add_const<T>::type > rr( r ); + return ( rr < l ); +# endif +} + +template< class T, class U > +gsl_NODISCARD inline gsl_constexpr14 bool +operator>=( basic_string_span<T> const & l, U const & r ) gsl_noexcept +{ + return !( l < r ); +} + +# if gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) + +template< class T, class U + gsl_ENABLE_IF_(( !detail::is_basic_string_span<U>::value )) +> +gsl_NODISCARD inline gsl_constexpr14 bool +operator!=( U const & l, basic_string_span<T> const & r ) gsl_noexcept +{ + return !( l == r ); +} + +template< class T, class U + gsl_ENABLE_IF_(( !detail::is_basic_string_span<U>::value )) +> +gsl_NODISCARD inline gsl_constexpr14 bool +operator<=( U const & l, basic_string_span<T> const & r ) gsl_noexcept +{ + return !( r < l ); +} + +template< class T, class U + gsl_ENABLE_IF_(( !detail::is_basic_string_span<U>::value )) +> +gsl_NODISCARD inline gsl_constexpr14 bool +operator>( U const & l, basic_string_span<T> const & r ) gsl_noexcept +{ + return ( r < l ); +} + +template< class T, class U + gsl_ENABLE_IF_(( !detail::is_basic_string_span<U>::value )) +> +gsl_NODISCARD inline gsl_constexpr14 bool +operator>=( U const & l, basic_string_span<T> const & r ) gsl_noexcept +{ + return !( l < r ); +} + +# endif // gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) + +# if gsl_FEATURE( BYTE ) +// convert basic_string_span to byte span: + +template< class T > +gsl_NODISCARD gsl_api inline span< const byte > +as_bytes( basic_string_span<T> spn ) gsl_noexcept +{ + return span< const byte >( reinterpret_cast<const byte *>( spn.data() ), spn.size_bytes() ); // NOLINT +} +# endif // gsl_FEATURE( BYTE ) +#endif // gsl_FEATURE( STRING_SPAN ) + +// +// String types: +// + +typedef char * zstring; +typedef const char * czstring; + +# if gsl_HAVE( WCHAR ) +typedef wchar_t * wzstring; +typedef const wchar_t * cwzstring; +# endif + +#if gsl_FEATURE( STRING_SPAN ) + +typedef basic_string_span< char > string_span; +typedef basic_string_span< char const > cstring_span; + +# if gsl_HAVE( WCHAR ) +typedef basic_string_span< wchar_t > wstring_span; +typedef basic_string_span< wchar_t const > cwstring_span; +# endif + +// to_string() allow (explicit) conversions from string_span to string + +# if 0 + +template< class T > +inline std::basic_string< typename std::remove_const<T>::type > to_string( basic_string_span<T> spn ) +{ + std::string( spn.data(), spn.length() ); +} + +# else + +gsl_NODISCARD inline std::string +to_string( string_span const & spn ) +{ + return std::string( spn.data(), static_cast<std::size_t>( spn.length() ) ); +} + +gsl_NODISCARD inline std::string +to_string( cstring_span const & spn ) +{ + return std::string( spn.data(), static_cast<std::size_t>( spn.length() ) ); +} + +# if gsl_HAVE( WCHAR ) + +gsl_NODISCARD inline std::wstring +to_string( wstring_span const & spn ) +{ + return std::wstring( spn.data(), static_cast<std::size_t>( spn.length() ) ); +} + +gsl_NODISCARD inline std::wstring +to_string( cwstring_span const & spn ) +{ + return std::wstring( spn.data(), static_cast<std::size_t>( spn.length() ) ); +} + +# endif // gsl_HAVE( WCHAR ) +# endif // to_string() + +// +// Stream output for string_span types +// + +namespace detail { + +template< class Stream > +void write_padding( Stream & os, std::streamsize n ) +{ + for ( std::streamsize i = 0; i < n; ++i ) + os.rdbuf()->sputc( os.fill() ); +} + +template< class Stream, class Span > +Stream & write_to_stream( Stream & os, Span const & spn ) +{ + typename Stream::sentry sentry( os ); + + if ( !os ) + return os; + + const std::streamsize length = gsl_lite::narrow_failfast<std::streamsize>( spn.length() ); + + // Whether, and how, to pad + const bool pad = ( length < os.width() ); + const bool left_pad = pad && ( os.flags() & std::ios_base::adjustfield ) == std::ios_base::right; + + if ( left_pad ) + detail::write_padding( os, os.width() - length ); + + // Write span characters + os.rdbuf()->sputn( spn.data(), length ); + + if ( pad && !left_pad ) + detail::write_padding( os, os.width() - length ); + + // Reset output stream width + os.width(0); + + return os; +} + +} // namespace detail + +template< typename Traits > +std::basic_ostream< char, Traits > & operator<<( std::basic_ostream< char, Traits > & os, string_span const & spn ) +{ + return detail::write_to_stream( os, spn ); +} + +template< typename Traits > +std::basic_ostream< char, Traits > & operator<<( std::basic_ostream< char, Traits > & os, cstring_span const & spn ) +{ + return detail::write_to_stream( os, spn ); +} + +# if gsl_HAVE( WCHAR ) + +template< typename Traits > +std::basic_ostream< wchar_t, Traits > & operator<<( std::basic_ostream< wchar_t, Traits > & os, wstring_span const & spn ) +{ + return detail::write_to_stream( os, spn ); +} + +template< typename Traits > +std::basic_ostream< wchar_t, Traits > & operator<<( std::basic_ostream< wchar_t, Traits > & os, cwstring_span const & spn ) +{ + return detail::write_to_stream( os, spn ); +} + +# endif // gsl_HAVE( WCHAR ) + +// +// ensure_sentinel() +// +// Provides a way to obtain a 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. +// +namespace detail { + +template< class T, class SizeType, const T Sentinel > +gsl_constexpr14 static span<T> ensure_sentinel( T * seq, SizeType max = (std::numeric_limits<SizeType>::max)() ) +{ + typedef T * pointer; + + gsl_SUPPRESS_MSVC_WARNING( 26429, "f.23: symbol 'cur' is never tested for nullness, it can be marked as not_null" ) + pointer cur = seq; + + while ( static_cast<SizeType>( cur - seq ) < max && *cur != Sentinel ) + ++cur; + + gsl_Expects( *cur == Sentinel ); + + return span<T>( seq, gsl_lite::narrow_cast< typename span<T>::index_type >( cur - seq ) ); +} +} // namespace detail + +// +// ensure_z - creates a string_span for a czstring or cwzstring. +// Will fail fast if a null-terminator cannot be found before +// the limit of size_type. +// + +template< class T > +gsl_NODISCARD inline gsl_constexpr14 span<T> +ensure_z( T * const & sz, size_t max = (std::numeric_limits<size_t>::max)() ) +{ + return detail::ensure_sentinel<T, size_t, 0>( sz, max ); +} + +template< class T, size_t N > +gsl_NODISCARD inline gsl_constexpr14 span<T> +ensure_z( T (&sz)[N] ) +{ + return ::gsl_lite::ensure_z( gsl_ADDRESSOF( sz[0] ), N ); +} + +# if gsl_HAVE( TYPE_TRAITS ) + +template< class Container > +gsl_NODISCARD inline gsl_constexpr14 span< typename std::remove_pointer<typename Container::pointer>::type > +ensure_z( Container & cont ) +{ + return ::gsl_lite::ensure_z( cont.data(), cont.length() ); +} +# endif + +// +// basic_zstring_span<> - A view of contiguous null-terminated characters, replace (*,len). +// + +template <typename T> +class basic_zstring_span +{ +public: + typedef T element_type; + typedef span<T> span_type; + + typedef typename span_type::index_type index_type; + typedef typename span_type::difference_type difference_type; + + typedef element_type * czstring_type; + typedef basic_string_span<element_type> string_span_type; + +# if gsl_DEPRECATE_TO_LEVEL( 7 ) + gsl_DEPRECATED_MSG("basic_zstring_span<> is deprecated") +# endif // gsl_DEPRECATE_TO_LEVEL( 7 ) + gsl_api gsl_constexpr14 basic_zstring_span( span_type s ) + : span_( s ) + { + // expects a zero-terminated span + gsl_Expects( s.back() == '\0' ); + } + +# if gsl_HAVE( IS_DEFAULT ) + gsl_constexpr basic_zstring_span( basic_zstring_span const & ) = default; + gsl_constexpr basic_zstring_span( basic_zstring_span && ) = default; + gsl_constexpr14 basic_zstring_span & operator=( basic_zstring_span const & ) = default; + gsl_constexpr14 basic_zstring_span & operator=( basic_zstring_span && ) = default; +# else + gsl_api gsl_constexpr basic_zstring_span( basic_zstring_span const & other) : span_ ( other.span_ ) {} + gsl_api gsl_constexpr basic_zstring_span & operator=( basic_zstring_span const & other ) { span_ = other.span_; return *this; } +# endif + + gsl_NODISCARD gsl_api gsl_constexpr bool + empty() const gsl_noexcept + { + return false; + } + +# if gsl_DEPRECATE_TO_LEVEL( 7 ) + gsl_DEPRECATED_MSG("basic_zstring_span<> is deprecated") +# endif // gsl_DEPRECATE_TO_LEVEL( 7 ) + gsl_NODISCARD gsl_api gsl_constexpr string_span_type + as_string_span() const gsl_noexcept + { + return string_span_type( span_.data(), span_.size() - 1 ); + } + +# if gsl_DEPRECATE_TO_LEVEL( 7 ) + gsl_DEPRECATED_MSG("basic_zstring_span<> is deprecated") +# endif // gsl_DEPRECATE_TO_LEVEL( 7 ) + /*gsl_api*/ // currently disabled due to an apparent NVCC bug + gsl_NODISCARD gsl_constexpr string_span_type + ensure_z() const + { + return ::gsl_lite::ensure_z(span_.data(), span_.size()); + } + + gsl_NODISCARD gsl_api gsl_constexpr czstring_type + assume_z() const gsl_noexcept + { + return span_.data(); + } + +private: + span_type span_; +}; + +// +// zString types: +// + +typedef basic_zstring_span< char > zstring_span; +typedef basic_zstring_span< char const > czstring_span; + +# if gsl_HAVE( WCHAR ) +typedef basic_zstring_span< wchar_t > wzstring_span; +typedef basic_zstring_span< wchar_t const > cwzstring_span; +# endif +#endif // gsl_FEATURE( STRING_SPAN ) + +} // namespace gsl_lite + +#if gsl_HAVE( HASH ) + +// +// std::hash specializations for GSL types +// + +namespace gsl_lite { + +namespace detail { + +// +// Helper struct for std::hash specializations +// + +template<bool Condition> +struct conditionally_enabled_hash +{ + +}; + +// disabled as described in [unord.hash] +template<> +struct conditionally_enabled_hash< false > +{ +gsl_is_delete_access: + conditionally_enabled_hash() gsl_is_delete; + conditionally_enabled_hash( conditionally_enabled_hash const & ) gsl_is_delete; + conditionally_enabled_hash( conditionally_enabled_hash && ) gsl_is_delete; + conditionally_enabled_hash & operator=( conditionally_enabled_hash const & ) gsl_is_delete; + conditionally_enabled_hash & operator=( conditionally_enabled_hash && ) gsl_is_delete; +}; + +} // namespace detail + +} // namespace gsl_lite + +namespace std { + +template< class T > +struct hash< ::gsl_lite::not_null< T > > : public ::gsl_lite::detail::conditionally_enabled_hash< is_default_constructible< hash< T > >::value > +{ +public: + gsl_NODISCARD std::size_t + operator()( ::gsl_lite::not_null<T> const & v ) const + // hash function is not `noexcept` because `as_nullable()` has preconditions + { + return hash<T>()( ::gsl_lite::as_nullable( v ) ); + } +}; +template< class T > +struct hash< ::gsl_lite::not_null< T* > > +{ +public: + gsl_NODISCARD std::size_t + operator()( ::gsl_lite::not_null< T* > const & v ) const gsl_noexcept + { + return hash<T*>()( ::gsl_lite::as_nullable( v ) ); + } +}; + +# if gsl_FEATURE( BYTE ) +template<> +struct hash< ::gsl_lite::byte > +{ +public: + gsl_NODISCARD std::size_t operator()( ::gsl_lite::byte v ) const gsl_noexcept + { +# if gsl_CONFIG_DEFAULTS_VERSION >= 1 + return std::hash<unsigned char>{ }( ::gsl_lite::to_uchar( v ) ); +# else // gsl_CONFIG_DEFAULTS_VERSION < 1 + // Keep the old hashing algorithm if legacy defaults are used. + return ::gsl_lite::to_integer<std::size_t>( v ); +# endif // gsl_CONFIG_DEFAULTS_VERSION >= 1 + } +}; +# endif // gsl_FEATURE( BYTE ) + +} // namespace std + +#endif // gsl_HAVE( HASH ) + +#if gsl_STDLIB_CPP11_OR_GREATER +namespace std { + +template< class T > +struct pointer_traits< ::gsl_lite::detail::span_iterator< T > > +{ + typedef ::gsl_lite::detail::span_iterator< T > pointer; + typedef T element_type; + typedef ptrdiff_t difference_type; + + static gsl_constexpr element_type * to_address( pointer const i ) gsl_noexcept { return i.current_; } +}; + +} // namespace std +#endif // gsl_STDLIB_CPP11_OR_GREATER + +#if gsl_FEATURE( GSL_COMPATIBILITY_MODE ) + +// Enable GSL compatibility mode by aliasing all symbols in the `gsl` namespace and defining the unprefixed +// macros `Expects()` and `Ensures()`. +// +// gsl-lite can generally coexist with Microsoft GSL. However, if GSL compatibility mode is enabled, +// gsl-lite cannot be used in the same translation unit as Microsoft GSL. +// (Link-time compatibility is unaffected; different translation units that use either Microsoft GSL +// or gsl-lite may be linked together.) + +namespace gsl = ::gsl_lite; + +#define Expects( x ) gsl_Expects( x ) +#define Ensures( x ) gsl_Ensures( x ) + +#endif // gsl_FEATURE( GSL_COMPATIBILITY_MODE ) + +gsl_RESTORE_MSVC_WARNINGS() +#if gsl_COMPILER_CLANG_VERSION || gsl_COMPILER_APPLECLANG_VERSION +# pragma clang diagnostic pop +#endif // gsl_COMPILER_CLANG_VERSION || gsl_COMPILER_APPLECLANG_VERSION +#if gsl_COMPILER_GNUC_VERSION +# pragma GCC diagnostic pop +#endif // gsl_COMPILER_GNUC_VERSION + +// #undef internal macros +#undef gsl_STATIC_ASSERT_ +#undef gsl_ENABLE_IF_R_ +#undef gsl_ENABLE_IF_NTTP_ +#undef gsl_ENABLE_IF_ +#undef gsl_TRAILING_RETURN_TYPE_ +#undef gsl_RETURN_DECLTYPE_ + +#endif // GSL_LITE_GSL_LITE_HPP_INCLUDED + +// end of file diff --git a/thirdparty/gsl-lite/include/gsl/gsl-lite.hpp b/thirdparty/gsl-lite/include/gsl/gsl-lite.hpp new file mode 100644 index 000000000..70b5486b5 --- /dev/null +++ b/thirdparty/gsl-lite/include/gsl/gsl-lite.hpp @@ -0,0 +1,43 @@ +// +// For more information see https://github.com/gsl-lite/gsl-lite +// +// gsl-lite is originally based on Microsoft GSL, which is an implementation of the C++ Core Guidelines Support Library: +// https://github.com/microsoft/GSL +// +// Copyright (c) 2015-2019 Martin Moene +// Copyright (c) 2019-2025 Moritz Beutel +// Copyright (c) 2015-2018 Microsoft Corporation. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef GSL_GSL_LITE_HPP_INCLUDED +#define GSL_GSL_LITE_HPP_INCLUDED + +#include <gsl-lite/gsl-lite.hpp> + +#if ! gsl_FEATURE( GSL_COMPATIBILITY_MODE ) + +# pragma message (__FILE__ "(" gsl_STRINGIFY( __LINE__ ) "): warning: The legacy header file <gsl/gsl-lite.hpp> implicitly enables gsl-lite's GSL compatibility mode, making namespace gsl and the Expects() and Ensures() macros available for backward compatibility. If possible, modernize your code by including the <gsl-lite/gsl-lite.hpp> header file, referring to namespace gsl_lite rather than namespace gsl, and using the prefixed contract checking macros gsl_Expects() and gsl_Ensures() instead of the unprefixed Expects() and Ensures(). If you wish to explicitly retain the GSL compatibility mode, define the macro gsl_FEATURE_GSL_COMPATIBILITY_MODE=1 in the build options.") + +// Implicitly enable the GSL compatbility mode. +# undef gsl_FEATURE_GSL_COMPATIBILITY_MODE +# define gsl_FEATURE_GSL_COMPATIBILITY_MODE 1 + +namespace gsl = ::gsl_lite; + +# define Expects( x ) gsl_Expects( x ) +# define Ensures( x ) gsl_Ensures( x ) + +#endif // ! gsl_FEATURE( GSL_COMPATIBILITY_MODE ) + +#endif // GSL_GSL_LITE_HPP_INCLUDED + +// end of file diff --git a/thirdparty/gsl-lite/src/gsl-lite.natvis b/thirdparty/gsl-lite/src/gsl-lite.natvis new file mode 100644 index 000000000..b73e9a03c --- /dev/null +++ b/thirdparty/gsl-lite/src/gsl-lite.natvis @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> + +<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010"> + <Type Name="gsl_lite::fail_fast"> + <!-- na hides the address, otherwise it would appear as 0x.... "Message" --> + <DisplayString>{_Data._What,nasb}</DisplayString> + </Type> + + <Type Name="gsl_lite::span<*>"> + <DisplayString>{{ size={last_ - first_} }}</DisplayString> + <Expand> + <Item Name="[size]">last_ - first_</Item> + <ArrayItems> + <Size>last_ - first_</Size> + <ValuePointer>first_</ValuePointer> + </ArrayItems> + </Expand> + </Type> + + <Type Name="gsl_lite::not_null<*>"> + <DisplayString>{data_.ptr_}</DisplayString> + <Expand> + <ExpandedItem>data_.ptr_</ExpandedItem> + </Expand> + </Type> +</AutoVisualizer> diff --git a/thirdparty/gsl-lite/test/MakeTestTarget.cmake b/thirdparty/gsl-lite/test/MakeTestTarget.cmake new file mode 100644 index 000000000..8f8bf1be5 --- /dev/null +++ b/thirdparty/gsl-lite/test/MakeTestTarget.cmake @@ -0,0 +1,331 @@ +# Copyright 2015-2019 by Martin Moene +# Copyright 2019-2021 by Moritz Beutel +# +# gsl-lite is based on GSL: Guidelines Support Library, +# https://github.com/microsoft/gsl +# +# This code is licensed under the MIT License (MIT). + + +if( DEFINED _makeTestTarget ) + return() # prevent multiple inclusion +endif() +set( _makeTestTarget ) + + + +# Configure gsl-lite for testing: + +set( GSL_CONFIG + "gsl_TESTING_" +) + +set( CUDA_OPTIONS ) + +# Preset available C++ language compiler flags: + +set( HAS_STD_FLAGS FALSE ) +set( HAS_CPP98_FLAG FALSE ) +set( HAS_CPP11_FLAG FALSE ) +set( HAS_CPP14_FLAG FALSE ) +set( HAS_CPP17_FLAG FALSE ) +set( HAS_CPP20_FLAG FALSE ) +set( HAS_CPPLATEST_FLAG FALSE ) + +# Preset available CUDA language compiler flags: + +set( HAS_CUDA14_FLAG FALSE ) +set( HAS_CUDA17_FLAG FALSE ) + +set( HOST_COMPILER_PREFIX "" ) + +# Determine compiler-specifics for MSVC, GNUC, Clang: + +if( MSVC ) + set( HAS_STD_FLAGS TRUE ) + + # remove "/EHx" from CMAKE_CXX_FLAGS if present + if( CMAKE_CXX_FLAGS MATCHES "/EH[ascr-]+" ) + string( REGEX REPLACE "/EH[ascr-]+" " " CMAKE_CXX_FLAGS_NEW "${CMAKE_CXX_FLAGS}" ) + set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS_NEW}" ) + endif() + + # remove "/Wx" from CMAKE_CXX_FLAGS if present + if( CMAKE_CXX_FLAGS MATCHES "/W[0-4]" ) + string( REGEX REPLACE "/W[0-4]" " " CMAKE_CXX_FLAGS_NEW "${CMAKE_CXX_FLAGS}" ) + set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS_NEW}" ) + endif() + + # clang-cl: available std flags depends on version + if( CMAKE_CXX_COMPILER_ID MATCHES "Clang" ) + message( STATUS "Matched: clang-cl ${CMAKE_CXX_COMPILER_VERSION}" ) + + if( NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.3.0 ) + set( HAS_CPP11_FLAG TRUE ) + endif() + if( NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.4.0 ) + set( HAS_CPP14_FLAG TRUE ) + endif() + if( NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.0.0 ) + set( HAS_CPP17_FLAG TRUE ) + set( HAS_CPPLATEST_FLAG TRUE ) + endif() + else() + message( STATUS "Matched: MSVC ${CMAKE_CXX_COMPILER_VERSION}" ) + if( NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19.00 ) + set( HAS_CPP14_FLAG TRUE ) + set( HAS_CPPLATEST_FLAG TRUE ) + endif() + if( NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19.11 ) + set( HAS_CPP17_FLAG TRUE ) + endif() + endif() + +# Older CMake versions identify NVHPC compilers as PGI. +elseif( CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang|AppleClang|PGI|NVHPC" ) + + set( HAS_STD_FLAGS TRUE ) + set( HAS_CPP98_FLAG TRUE ) + + # GNU: available -std flags depends on version + if( CMAKE_CXX_COMPILER_ID MATCHES "GNU" ) + message( STATUS "Matched: GNU ${CMAKE_CXX_COMPILER_VERSION}" ) + + if( NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.7.0 ) + set( HAS_CPP11_FLAG TRUE ) + endif() + if( NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.9.2 ) + set( HAS_CPP14_FLAG TRUE ) + endif() + if( NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 7.1.0 ) + set( HAS_CPP17_FLAG TRUE ) + endif() + if( NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 10.0.0 ) + set( HAS_CPP20_FLAG TRUE ) + endif() + + # AppleClang: available -std flags depends on version + elseif( CMAKE_CXX_COMPILER_ID MATCHES "AppleClang" ) + message( STATUS "Matched: AppleClang ${CMAKE_CXX_COMPILER_VERSION}" ) + + if( NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.0.0 ) + set( HAS_CPP11_FLAG TRUE ) + endif() + if( NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.1.0 ) + set( HAS_CPP14_FLAG TRUE ) + endif() + if( NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 9.2.0 ) + set( HAS_CPP17_FLAG TRUE ) + endif() + + # Clang: available -std flags depends on version + elseif( CMAKE_CXX_COMPILER_ID MATCHES "Clang" ) + message( STATUS "Matched: Clang ${CMAKE_CXX_COMPILER_VERSION}" ) + + if( NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.3.0 ) + set( HAS_CPP11_FLAG TRUE ) + endif() + if( NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.4.0 ) + set( HAS_CPP14_FLAG TRUE ) + endif() + if( NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.0.0 ) + set( HAS_CPP17_FLAG TRUE ) + endif() + if( NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 10.0.0 ) + set( HAS_CPP20_FLAG TRUE ) + endif() + # Older CMake versions identify NVHPC compilers as PGI. + elseif( CMAKE_CXX_COMPILER_ID MATCHES "PGI|NVHPC" ) + message( STATUS "Matched: NVHPC/PGI ${CMAKE_CXX_COMPILER_VERSION}" ) + set( HAS_CPP11_FLAG TRUE ) + set( HAS_CPP14_FLAG TRUE ) + set( HAS_CPP17_FLAG TRUE ) + set( HAS_CPP20_FLAG TRUE ) + endif() +elseif( CMAKE_CXX_COMPILER_ID MATCHES "Intel" ) + message( STATUS "Matched: Intel ${CMAKE_CXX_COMPILER_VERSION}" ) +else() + message( STATUS "Matched: nothing (CompilerId: '${CMAKE_CXX_COMPILER_ID}')") +endif() + +# Determine compiler-specifics for NVCC: + +get_property( _languages GLOBAL PROPERTY ENABLED_LANGUAGES ) +if( CUDA IN_LIST _languages ) + if( CMAKE_CUDA_COMPILER_ID MATCHES "NVIDIA" ) + message( STATUS "Matched: NVCC ${CMAKE_CUDA_COMPILER_VERSION}" ) + + # Set NVCC-specific options: + set( HOST_COMPILER_PREFIX "-Xcompiler=" ) + list( APPEND CUDA_OPTIONS "--Werror" "all-warnings" "-G" ) + + set( HAS_CUDA14_FLAG TRUE ) + if( CMAKE_CUDA_COMPILER_VERSION VERSION_GREATER_EQUAL 11.0 ) + set( HAS_CUDA17_FLAG TRUE ) + endif() + endif() +endif() + +# Enable MS C++ Core Guidelines checker if MSVC (but only when using MSBuild because Ninja cannot find the <CppCoreCheck/warnings.h> header): + +function( enable_msvs_guideline_checker target ) + if( MSVC AND CMAKE_GENERATOR MATCHES "Visual Studio" ) + target_compile_definitions( ${target} PRIVATE gsl_TESTING_CPPCORECHECK_ ) + set_target_properties( ${target} PROPERTIES + VS_GLOBAL_EnableCppCoreCheck true + VS_GLOBAL_CodeAnalysisRuleSet CppCoreCheckRules.ruleset + VS_GLOBAL_RunCodeAnalysis true ) + endif() +endfunction() + +# Make target, compile for given standard if specified: + +function( make_test_target target ) + + set( optionArgs CUDA NO_EXCEPTIONS COMPILE_ONLY NO_PCH ) + set( oneValueArgs STD DEFAULTS_VERSION CONTRACT_VIOLATION CONTRACT_CHECKING UNENFORCED_CONTRACTS ) + set( multiValueArgs SOURCES EXTRA_OPTIONS ) + cmake_parse_arguments( "SCOPE" "${optionArgs}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} ) + if( SCOPE_UNPARSED_ARGUMENTS ) + list( JOIN SCOPE_UNPARSED_ARGUMENTS "\", \"" SCOPE_UNPARSED_ARGUMENTS_STR ) + list( JOIN "${oneValueArgs};${multiValueArgs}" "\", \"" POSSIBLE_ARGUMENTS_STR ) + message( SEND_ERROR "make_test_target(): Invalid argument keyword(s) \"${SCOPE_UNPARSED_ARGUMENTS_STR}\"; expected one of \"${POSSIBLE_ARGUMENTS_STR}\"" ) + endif() + if( SCOPE_KEYWORDS_MISSING_VALUES ) + list( JOIN SCOPE_KEYWORDS_MISSING_VALUES "\", \"" SCOPE_KEYWORDS_MISSING_VALUES_STR ) + message( SEND_ERROR "make_test_target(): argument keyword(s) \"${SCOPE_KEYWORDS_MISSING_VALUES_STR}\" missing values" ) + endif() + if( NOT DEFINED SCOPE_SOURCES ) + message( SEND_ERROR "make_test_target(): no argument specified for SCOPE_SOURCES" ) + endif() + if( NOT DEFINED SCOPE_DEFAULTS_VERSION ) + message( SEND_ERROR "make_test_target(): no argument specified for DEFAULTS_VERSION" ) + endif() + if( NOT DEFINED SCOPE_CONTRACT_VIOLATION ) + set( SCOPE_CONTRACT_VIOLATION "THROWS" ) + endif() + if( NOT DEFINED SCOPE_CONTRACT_CHECKING ) + set( SCOPE_CONTRACT_CHECKING "ON" ) + endif() + if( NOT DEFINED SCOPE_UNENFORCED_CONTRACTS ) + set( SCOPE_UNENFORCED_CONTRACTS "ELIDE" ) + endif() + + message( STATUS "Make target: '${target}'" ) + + add_executable( ${target} ${SCOPE_SOURCES} ) + + set( localOptions ${OPTIONS} ) + set( localDefinitions ${GSL_CONFIG} "gsl_CONFIG_CONTRACT_VIOLATION_${SCOPE_CONTRACT_VIOLATION}" "gsl_CONFIG_UNENFORCED_CONTRACTS_${SCOPE_UNENFORCED_CONTRACTS}" ) + + if( SCOPE_CONTRACT_CHECKING ) + list( APPEND localDefinitions "gsl_CONFIG_CONTRACT_CHECKING_AUDIT" ) + else() + list( APPEND localDefinitions "gsl_CONFIG_CONTRACT_CHECKING_OFF" ) + endif() + + if( MSVC ) + list( APPEND localOptions "/WX" "/W4" ) + list( APPEND localOptions "/w44062" ) # enable C4062: enumerator 'identifier' in a switch of enum 'enumeration' is not handled + list( APPEND localOptions "/w44242" ) # enable C4242: 'identifier': conversion from 'type1' to 'type2', possible loss of data + list( APPEND localOptions "/w44254" ) # enable C4254: 'operator': conversion from 'type1' to 'type2', possible loss of data + list( APPEND localOptions "/w44265" ) # enable C4265: 'class': class has virtual functions, but destructor is not virtual + list( APPEND localDefinitions "_SCL_SECURE_NO_WARNINGS" ) + if( CMAKE_CXX_COMPILER_ID STREQUAL "MSVC" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 17.0 ) # VC++ 2010 and earlier + list( APPEND localOptions "/wd4127" ) # disable C4127: conditional expression is constant + list( APPEND localOptions "/wd4275" ) # disable C4275: non dll-interface class 'stdext::exception' used as base for dll-interface class 'std::bad_cast' + endif() + if ( CMAKE_CXX_COMPILER_ID STREQUAL "MSVC" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 18.0 ) # VC++ 2012 and earlier + list( APPEND localOptions "/wd4345" ) # disable C4345: behavior change: an object of POD type constructed with an initializer of the form () will be default-initialized [actually, value-initialized] + endif() + if( CMAKE_CXX_COMPILER_ID STREQUAL "MSVC" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19.1 AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19.0 ) # VC++ 2015 + list( APPEND localOptions "/wd4577" ) # disable C4577: 'noexcept' used with no exception handling mode specified; termination on exception is not guaranteed. Specify /EHsc + list( APPEND localOptions "/wd4702" ) # disable C4702: unreachable code + endif() + elseif( CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang|AppleClang" ) + list( APPEND localOptions + "-Werror" + "-Wall" + "-Wextra" + #"-Wno-missing-braces" + "-Wconversion" + "-Wsign-conversion" + "-fno-elide-constructors" + "-fstrict-aliasing" "-Wstrict-aliasing=2" + ) + if( NOT SCOPE_CUDA ) + list( APPEND localOptions "-pedantic" ) # NVCC and "-pedantic" don't mix (GCC complains that NVCC-generated GCC-specific code is GCC specific) + endif() + if( CMAKE_CXX_COMPILER_ID MATCHES "GNU" ) + list( APPEND localOptions + "-Wno-long-long" # irrelevant strict-C++98 warning about non-standard type `long long` + "-Wuseless-cast" # leads to warnings that need to be suppressed, cf. https://github.com/gsl-lite/gsl-lite/issues/325 + ) + if( CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.8 ) + list( APPEND localOptions "-Wno-type-limits" ) # irrelevant warning about `unsigned value < 0` comparison + endif() + if( NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 10.0 ) + list( APPEND localOptions "-Wno-error=array-bounds" ) # work around compiler bug: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100137 + endif() + elseif( CMAKE_CXX_COMPILER_ID MATCHES "Clang|AppleClang" ) + list( APPEND localOptions + "-Wno-c++11-long-long" # irrelevant strict-C++98 warning about non-standard type `long long` + "-Wweak-vtables" # leads to warnings that need to be suppressed, cf. https://github.com/gsl-lite/gsl-lite/issues/322 + ) + endif() + endif() + + if( SCOPE_NO_EXCEPTIONS ) + if( MSVC ) + list( APPEND localOptions "/EHs-" ) + list( APPEND localDefinitions "_HAS_EXCEPTIONS=0" ) + elseif( CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang|AppleClang" ) + list( APPEND localOptions "-fno-exceptions" ) + endif() + else() + if( MSVC ) + list( APPEND localOptions "/EHsc" ) + endif() + endif() + + if( SCOPE_STD ) + if( MSVC ) + list( APPEND localOptions "/std:c++${SCOPE_STD}" ) + else() + list( APPEND localOptions "-std=c++${SCOPE_STD}" ) + endif() + endif() + + if( SCOPE_CUDA ) + list( TRANSFORM localOptions PREPEND "${HOST_COMPILER_PREFIX}" ) + target_compile_options( ${target} PRIVATE ${CUDA_OPTIONS} ) + if( SCOPE_STD ) + set_target_properties( ${target} PROPERTIES CUDA_STANDARD ${SCOPE_STD} ) + endif() + endif() + + target_compile_options( ${target} PRIVATE ${localOptions} ${SCOPE_EXTRA_OPTIONS} ) + target_compile_definitions( ${target} PRIVATE ${localDefinitions} ) + target_link_libraries( ${target} PRIVATE gsl-lite-${SCOPE_DEFAULTS_VERSION} ) + + if( NOT SCOPE_NO_PCH + AND NOT CMAKE_VERSION VERSION_LESS 3.16 # VERSION_GREATER_EQUAL doesn't exist in CMake 3.5 + AND NOT ( CMAKE_CXX_COMPILER_ID MATCHES "GNU" AND CMAKE_SYSTEM_NAME MATCHES "Darwin" ) ) # and GCC on MacOS has trouble with addresses of some text segments in the PCH + target_precompile_headers( ${target} + PRIVATE + <gsl-lite/gsl-lite.hpp> + <ostream> + <sstream> + <iostream> + <cstring> + ) + endif() + + if( NOT SCOPE_COMPILE_ONLY ) + # We only add tests for targets with exceptions enabled. lest has been modified to permit compilation without exceptions + # so we can test compiling gsl-lite without exceptions, but the no-exception tests will not run correctly because lest + # relies on exceptions for running tests and therefore cannot function correctly without. + add_test( NAME ${target} COMMAND ${target} ) + endif() + +endfunction() diff --git a/thirdparty/gsl-lite/test/assert.t.cpp b/thirdparty/gsl-lite/test/assert.t.cpp new file mode 100644 index 000000000..d2957f392 --- /dev/null +++ b/thirdparty/gsl-lite/test/assert.t.cpp @@ -0,0 +1,229 @@ +// +// gsl-lite is based on GSL: Guidelines Support Library. +// For more information see https://github.com/gsl-lite/gsl-lite +// +// Copyright (c) 2015-2019 Martin Moene +// Copyright (c) 2019-2021 Moritz Beutel +// Copyright (c) 2015-2018 Microsoft Corporation. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "gsl-lite.t.hpp" + +#include <vector> + +namespace { + +bool expects( bool x ) { gsl_Expects( x ); return x; } +bool ensures( bool x ) { gsl_Ensures( x ); return x; } +bool assert_( bool x ) { gsl_Assert( x ); return x; } +void failFast() { gsl_FailFast(); } +bool expectsDebug( bool x ) { gsl_ExpectsDebug( x ); return x; } +bool ensuresDebug( bool x ) { gsl_EnsuresDebug( x ); return x; } +bool assertDebug( bool x ) { gsl_AssertDebug( x ); return x; } +bool expectsAudit( bool x ) { gsl_ExpectsAudit( x ); return x; } +bool ensuresAudit( bool x ) { gsl_EnsuresAudit( x ); return x; } +bool assertAudit( bool x ) { gsl_AssertAudit( x ); return x; } + +enum Color +#if gsl_CPP11_OR_GREATER +: int +#endif +{ red, green, blue }; + +#if gsl_COMPILER_NVHPC_VERSION && !gsl_CPP11_OR_GREATER +# pragma diag_suppress 941 // Suppress: missing return statement at end of non-void function "..." +#endif +std::string colorToString( Color color ) +{ + switch (color) + { + case red: return "red"; + case green: return "green"; + case blue: return "blue"; + } + gsl_FailFast(); // this should keep the compiler from issuing a warning about not returning a value +} +#if gsl_COMPILER_NVHPC_VERSION && !gsl_CPP11_OR_GREATER +# pragma diag_default 941 +#endif + + +struct ConvertibleToBool +{ +#if gsl_CPP11_OR_GREATER + explicit +#endif + operator bool(void) const gsl_noexcept { return true; } +}; + + +} // anonymous namespace + +CASE( "gsl_Expects(): Allows a true expression" ) +{ + EXPECT_NO_THROW( expects( true ) ); +} + +CASE( "gsl_Ensures(): Allows a true expression" ) +{ + EXPECT_NO_THROW( ensures( true ) ); +} + +CASE( "gsl_Assert(): Allows a true expression" ) +{ + EXPECT_NO_THROW( assert_( true ) ); +} + +CASE( "gsl_Expects(): Terminates on a false expression" ) +{ + EXPECT_THROWS( expects( false ) ); +} + +CASE( "gsl_Ensures(): Terminates on a false expression" ) +{ + EXPECT_THROWS( ensures( false ) ); +} + +CASE( "gsl_Assert(): Terminates on a false expression" ) +{ + EXPECT_THROWS( assert_( false ) ); +} + +CASE( "gsl_FailFast(): Suppresses compiler warning about missing return value" ) +{ + EXPECT( colorToString(red) == "red" ); +} + +CASE( "gsl_FailFast(): Terminates" ) +{ + EXPECT_THROWS( failFast() ); +#if gsl_CPP11_OR_GREATER + EXPECT_THROWS( colorToString( Color( 42 ) ) ); +#endif +} + +CASE( "gsl_ExpectsDebug(): Allows a true expression" ) +{ + EXPECT_NO_THROW( expectsDebug( true ) ); +} + +CASE( "gsl_EnsuresDebug(): Allows a true expression" ) +{ + EXPECT_NO_THROW( ensuresDebug( true ) ); +} + +CASE( "gsl_AssertDebug(): Allows a true expression" ) +{ + EXPECT_NO_THROW( assertDebug( true ) ); +} + +CASE( "gsl_ExpectsDebug(): Terminates on a false expression in debug build or AUDIT mode" ) +{ +#if !defined( NDEBUG ) || defined( gsl_CONFIG_CONTRACT_CHECKING_AUDIT ) + EXPECT_THROWS( expectsDebug( false ) ); +#else + EXPECT_NO_THROW( expectsDebug( false ) ); +#endif +} + +CASE( "gsl_EnsuresAudit(): Terminates on a false expression in debug build or AUDIT mode" ) +{ +#if !defined( NDEBUG ) || defined( gsl_CONFIG_CONTRACT_CHECKING_AUDIT ) + EXPECT_THROWS( ensuresDebug( false ) ); +#else + EXPECT_NO_THROW( ensuresDebug( false ) ); +#endif +} + +CASE( "gsl_AssertAudit(): Terminates on a false expression in debug build or AUDIT mode" ) +{ +#if !defined( NDEBUG ) || defined( gsl_CONFIG_CONTRACT_CHECKING_AUDIT ) + EXPECT_THROWS( assertDebug( false ) ); +#else + EXPECT_NO_THROW( assertDebug( false ) ); +#endif +} + +CASE( "gsl_ExpectsAudit(): Allows a true expression" ) +{ + EXPECT_NO_THROW( expectsAudit( true ) ); +} + +CASE( "gsl_EnsuresAudit(): Allows a true expression" ) +{ + EXPECT_NO_THROW( ensuresAudit( true ) ); +} + +CASE( "gsl_AssertAudit(): Allows a true expression" ) +{ + EXPECT_NO_THROW( assertAudit( true ) ); +} + +CASE( "gsl_ExpectsAudit(): Terminates on a false expression in AUDIT mode" ) +{ +#if defined( gsl_CONFIG_CONTRACT_CHECKING_AUDIT ) + EXPECT_THROWS( expectsAudit( false ) ); +#else + EXPECT_NO_THROW( expectsAudit( false ) ); +#endif +} + +CASE( "gsl_EnsuresAudit(): Terminates on a false expression in AUDIT mode" ) +{ +#if defined( gsl_CONFIG_CONTRACT_CHECKING_AUDIT ) + EXPECT_THROWS( ensuresAudit( false ) ); +#else + EXPECT_NO_THROW( ensuresAudit( false ) ); +#endif +} + +CASE( "gsl_AssertAudit(): Terminates on a false expression in AUDIT mode" ) +{ +#if defined( gsl_CONFIG_CONTRACT_CHECKING_AUDIT ) + EXPECT_THROWS( assertAudit( false ) ); +#else + EXPECT_NO_THROW( assertAudit( false ) ); +#endif +} + +int myAt( int i, std::vector<int> const& v ) +{ + // The arguments to `__assume( x )` (MSVC) and `__builtin_assume( x )` (Clang) are never evaluated, so they cannot incur side-effects. We would like to implement + // `gsl_ASSUME_()` in terms of these. However, Clang always emits a diagnostic if a potential side-effect is discarded, and every call to a function not annotated + // `__attribute__ ((pure))` or `__attribute__ ((const))` is considered a potential side-effect (e.g. the call to `v.size()` below). In many cases Clang is capable + // of inlining the expression and find it free of side-effects, cf. https://gcc.godbolt.org/z/ZcKfbp, but the warning is produced anyway. + // + // To avoid littering user code with warnings, we instead define `gsl_ASSUME_()` in terms of `__builtin_unreachable()`. The following `gsl_ASSUME_()` statement + // should thus compile without any warnings. + + gsl_Expects( i >= 0 && static_cast<std::size_t>(i) < v.size() ); + return v.at( static_cast<std::size_t>(i) ); +} + +CASE( "gsl_Expects(): No warnings produced for function calls in precondition checks" ) +{ + std::vector<int> v; + v.push_back( 42 ); + EXPECT_NO_THROW( myAt( 0, v ) ); + EXPECT_THROWS( myAt( 1, v ) ); +} + +CASE( "gsl_Expects(): Supports explicit conversions to bool" ) +{ + // `gsl_Expects()` should be compatible with explicit conversions to bool. + gsl_Expects( ConvertibleToBool() ); + + if ( ConvertibleToBool() ) { } // to get rid of weird NVCC warning about never-referenced conversion operator +} + + +// end of file diff --git a/thirdparty/gsl-lite/test/at.t.cpp b/thirdparty/gsl-lite/test/at.t.cpp new file mode 100644 index 000000000..c011daa75 --- /dev/null +++ b/thirdparty/gsl-lite/test/at.t.cpp @@ -0,0 +1,163 @@ +// +// gsl-lite is based on GSL: Guidelines Support Library. +// For more information see https://github.com/gsl-lite/gsl-lite +// +// Copyright (c) 2015-2019 Martin Moene +// Copyright (c) 2019-2021 Moritz Beutel +// Copyright (c) 2015-2018 Microsoft Corporation. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "gsl-lite.t.hpp" + +using namespace gsl_lite; + +CASE( "at(): Terminates access to non-existing C-array elements" ) +{ + int a[] = { 1, 2, 3, 4 }; + + EXPECT_THROWS( (void) at(a, 4) ); +} + +CASE( "at(): Terminates access to non-existing std::array elements (C++11)" ) +{ +#if gsl_HAVE( ARRAY ) + std::array<int, 4> a = {{ 1, 2, 3, 4 }}; + + EXPECT_THROWS( (void) at(a, 4) ); +#else + EXPECT( !!"std::array<> is not available (no C++11)" ); +#endif +} + +CASE( "at(): Terminates access to non-existing std::vector elements" ) +{ + std::vector<int> a; // = { 1, 2, 3, 4 }; + + for ( int i = 0; i < 4; ++i ) + { + a.push_back( i + 1 ); + } + + EXPECT_THROWS( (void) at(a, 4) ); +} + +CASE( "at(): Terminates access to non-existing std::initializer_list elements (C++11)" ) +{ +// Note: GCC 4.6.3 has std::initializer_list but selects at(Cont & cont,...) overload. + +#if gsl_HAVE( INITIALIZER_LIST ) && ( !gsl_COMPILER_GNUC_VERSION || gsl_COMPILER_GNUC_VERSION >= 473 ) + std::initializer_list<int> a = { 1, 2, 3, 4 }; + + EXPECT_THROWS( (void) at(a, 4) ); +#else + EXPECT( !!"std::initializer_list<> is not available (no C++11)" ); +#endif +} + +CASE( "at(): Terminates access to non-existing gsl_lite::span elements" ) +{ + int arr[] = { 1, 2, 3, 4 }; + span<int> a( arr ); + + EXPECT_THROWS( (void) at(a, 4) ); +} + +CASE( "at(): Allows to access existing C-array elements" ) +{ + size_t a[] = { 1, 2, 3, 4 }; + size_t const b[] = { 1, 2, 3, 4 }; + + for ( size_t i = 0; i < 4; ++i ) + { + EXPECT( at(a, i) == i + 1 ); + EXPECT( at(b, i) == i + 1 ); + } +} + +CASE( "at(): Allows to access existing std::array elements (C++11)" ) +{ +#if gsl_HAVE( ARRAY ) + std::array<size_t, 4> a = {{ 1, 2, 3, 4 }}; + std::array<size_t, 4> const b = {{ 1, 2, 3, 4 }}; + std::array<size_t const, 4> c = {{ 1, 2, 3, 4 }}; + + for ( size_t i = 0; i < 4; ++i ) + { + EXPECT( at(a, i) == i + 1 ); + EXPECT( at(b, i) == i + 1 ); + EXPECT( at(c, i) == i + 1 ); + } +#else + EXPECT( !!"std::array<> is not available (no C++11)" ); +#endif +} + +namespace { + +std::vector<size_t> make_vector( size_t N ) +{ + std::vector<size_t> v; + for ( size_t i = 0; i < N; ++i ) + { + v.push_back( i + 1 ); + } + return v; +} +} + +CASE( "at(): Allows to access existing std::vector elements" ) +{ + std::vector<size_t> a = make_vector( 4 ); // = { 1, 2, 3, 4 }; + std::vector<size_t> const b = make_vector( 4 ); // = { 1, 2, 3, 4 }; + + for ( size_t i = 0; i < 4; ++i ) + { + EXPECT( at(a, i) == i + 1 ); + EXPECT( at(b, i) == i + 1 ); + } +} + +CASE( "at(): Allows to access std::initializer_list elements (C++11)" ) +{ +// Note: GCC 4.6.3 has std::initializer_list but selects at(Cont & cont,...) overload. + +#if gsl_HAVE( INITIALIZER_LIST ) && ( !gsl_COMPILER_GNUC_VERSION || gsl_COMPILER_GNUC_VERSION >= 473 ) + std::initializer_list<size_t> a = { 1, 2, 3, 4 }; + std::initializer_list<size_t> const b = { 1, 2, 3, 4 }; + + for ( size_t i = 0; i < 4; ++i ) + { + EXPECT( at(a, i) == i + 1 ); + EXPECT( at(b, i) == i + 1 ); + } +#else + EXPECT( !!"std::initializer_list<> is not available (no C++11)" ); +#endif +} + +CASE( "at(): Allows to access gsl_lite::span elements" ) +{ + size_t arr[] = { 1, 2, 3, 4 }; + size_t const carr[] = { 1, 2, 3, 4 }; + span<size_t> a( arr ); + span<size_t> const b( arr ); + span<size_t const> c( carr ); + + for ( size_t i = 0; i < 4; ++i ) + { + EXPECT( at(a, i) == i + 1 ); + EXPECT( at(b, i) == i + 1 ); + EXPECT( at(c, i) == i + 1 ); + } +} + +// end of file diff --git a/thirdparty/gsl-lite/test/byte.t.cpp b/thirdparty/gsl-lite/test/byte.t.cpp new file mode 100644 index 000000000..07cc7169e --- /dev/null +++ b/thirdparty/gsl-lite/test/byte.t.cpp @@ -0,0 +1,216 @@ +// +// gsl-lite is based on GSL: Guidelines Support Library. +// For more information see https://github.com/gsl-lite/gsl-lite +// +// Copyright (c) 2015-2019 Martin Moene +// Copyright (c) 2019-2021 Moritz Beutel +// Copyright (c) 2015-2018 Microsoft Corporation. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "gsl-lite.t.hpp" + +using namespace gsl_lite; + +#if gsl_FEATURE( BYTE ) + +// Use gsl_lite::byte instead of plain byte to prevent collisions with +// other byte declarations, such as in rpcndr.h (Windows kit). + +// We have a chicken & egg problem here: +// verifying operations via to_integer() that has yet to verified itself... + +CASE( "byte: Allows to construct from integral via static cast (C++17)" ) +{ +# if gsl_HAVE( ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE ) + gsl_lite::byte b = static_cast<gsl_lite::byte>( 4 ); + EXPECT( static_cast<unsigned char>(b) == 4 ); + EXPECT( to_integer<int>( b ) == 4 ); +# else + EXPECT( !!"enum class is not constructible from underlying type (no C++17)" ); +# endif +} + +CASE( "byte: Allows to construct from integral via byte() (C++17)" ) +{ +# if gsl_HAVE( ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE ) + gsl_lite::byte b = gsl_lite::byte( 4 ); + EXPECT( to_integer<int>( b ) == 4 ); +# else + EXPECT( !!"enum class is not constructible from underlying type (no C++17)" ); +# endif +} + +CASE( "byte: Allows to construct from integral via to_byte()" ) +{ + gsl_lite::byte b = to_byte( 4 ); + EXPECT( to_integer<int>( b ) == 4 ); +} + +CASE( "byte: Allows to convert to integral via to_integer()" ) +{ + gsl_lite::byte b = to_byte( 4 ); + EXPECT( to_integer<int>( b ) == 4 ); +} + +CASE( "byte: Allows comparison operations" ) +{ + gsl_lite::byte a = to_byte( 3 ); + gsl_lite::byte b = to_byte( 7 ); + + EXPECT( a == a ); + EXPECT( a != b ); + + EXPECT( a < b ); + EXPECT( a <= a ); + EXPECT( a <= b ); + + EXPECT( b > a ); + EXPECT( b >= a ); + EXPECT( b >= b ); + + EXPECT_NOT( a == b ); + EXPECT_NOT( a != a ); + EXPECT_NOT( b < a ); + EXPECT_NOT( a > b ); +} + +CASE( "byte: Allows bitwise or operation" ) +{ + gsl_lite::byte const b = to_byte( 0xa5 ); + + EXPECT( ( b | b ) == b ); + EXPECT( ( b | to_byte( 0x00 ) ) == b ); + EXPECT( ( b | to_byte( 0xff ) ) == to_byte( 0xff ) ); +} + +CASE( "byte: Allows bitwise and operation" ) +{ + gsl_lite::byte const b = to_byte( 0xa5 ); + + EXPECT( ( b & b ) == b ); + EXPECT( ( b & to_byte( 0xff ) ) == b ); + EXPECT( ( b & to_byte( 0x00 ) ) == to_byte( 0x00 ) ); +} + +CASE( "byte: Allows bitwise x-or operation" ) +{ + gsl_lite::byte const b = to_byte( 0xa5 ); + + EXPECT( ( b ^ b ) == to_byte( 0 ) ); + EXPECT( ( b ^ to_byte( 0x00 ) ) == b ); + EXPECT( ( b ^ to_byte( 0xff ) ) == ~b ); +} + +CASE( "byte: Allows bitwise or assignment" ) +{ + SETUP("") { + + gsl_lite::byte const b_org = to_byte( 0xa5 ); + gsl_lite::byte b = b_org; + + SECTION("Identity") { EXPECT( ( b |= b ) == b_org ); } + SECTION("Identity") { EXPECT( ( b |= to_byte( 0x00 ) ) == b_org ); } + SECTION("Saturate") { EXPECT( ( b |= to_byte( 0xff ) ) == to_byte( 0xff ) ); } + } +} + +CASE( "byte: Allows bitwise and assignment" ) +{ + SETUP("") { + + gsl_lite::byte const b_org = to_byte( 0xa5 ); + gsl_lite::byte b = b_org; + + SECTION("Identity") { EXPECT( ( b &= b ) == b_org ); } + SECTION("Identity") { EXPECT( ( b &= to_byte( 0xff ) ) == b_org ); } + SECTION("Clear" ) { EXPECT( ( b &= to_byte( 0x00 ) ) == to_byte( 0x00 ) ); } + } +} + +CASE( "byte: Allows bitwise x-or assignment" ) +{ + SETUP("") { + + gsl_lite::byte const b_org = to_byte( 0xa5 ); + gsl_lite::byte b = b_org; + + SECTION("Identity") { EXPECT( ( b ^= b ) == to_byte( 0 ) ); } + SECTION("Identity") { EXPECT( ( b ^= to_byte( 0x00 ) ) == b_org ); } + SECTION("Invert" ) { EXPECT( ( b ^= to_byte( 0xff ) ) == ~b_org ); } + } +} + +CASE( "byte: Allows shift-left operation" ) +{ + gsl_lite::byte const b = to_byte( 0xa5 ); + + EXPECT( ( b << 3 ) == to_byte( to_uchar( b ) << 3 ) ); +} + +CASE( "byte: Allows shift-right operation" ) +{ + gsl_lite::byte const b = to_byte( 0xa5 ); + + EXPECT( ( b >> 3 ) == to_byte( to_uchar( b ) >> 3 ) ); +} + +CASE( "byte: Allows shift-left assignment" ) +{ + gsl_lite::byte const b_org = to_byte( 0xa5 ); + gsl_lite::byte b = b_org; + + EXPECT( ( b <<= 3 ) == to_byte( to_uchar( b_org ) << 3 ) ); +} + +CASE( "byte: Allows shift-right assignment" ) +{ + gsl_lite::byte const b_org = to_byte( 0xa5 ); + gsl_lite::byte b = b_org; + + EXPECT( ( b >>= 3 ) == to_byte( to_uchar( b_org ) >> 3 ) ); +} + +CASE( "byte: Provides constexpr non-assignment operations (C++11)" ) +{ +# if gsl_HAVE( CONSTEXPR_11 ) + static_assert( to_byte( 0xa5 ) == to_byte( 0xa5 ) , "" ); + static_assert( 0xa5 == to_integer<int>( to_byte( 0xa5 ) ), "" ); + + static_assert( to_byte( 0x02 ) == ( to_byte( 0x01 ) << 1 ), "" ); + static_assert( to_byte( 0x01 ) == ( to_byte( 0x02 ) >> 1 ), "" ); + + static_assert( to_byte( 0x01 ) == ( to_byte( 0x03 ) & to_byte( 0x01 ) ), "" ); + static_assert( to_byte( 0x01 ) == ( to_byte( 0x00 ) | to_byte( 0x01 ) ), "" ); + static_assert( to_byte( 0x00 ) == ( to_byte( 0x01 ) ^ to_byte( 0x01 ) ), "" ); + + static_assert( to_byte( 0xff ) == ~to_byte( 0x00 ), "" ); +# endif +} + +CASE( "byte: Provides constexpr assignment operations (C++14)" ) +{ +# if gsl_HAVE( CONSTEXPR_14 ) +// ... +# endif +} + +CASE( "byte: Provides hash support (C++11)" ) +{ +# if gsl_HAVE( HASH ) + EXPECT_NO_THROW( (void) std::hash<gsl_lite::byte>{}( to_byte( 42 ) ) ); +# else + EXPECT( !!"hash support is not available (no C++11)" ); +# endif +} +#endif // gsl_FEATURE( BYTE ) + +// end of file diff --git a/thirdparty/gsl-lite/test/core_check.t.cpp b/thirdparty/gsl-lite/test/core_check.t.cpp new file mode 100644 index 000000000..ad0ae00f6 --- /dev/null +++ b/thirdparty/gsl-lite/test/core_check.t.cpp @@ -0,0 +1,85 @@ + +#include <tuple> // for ignore +#include <vector> +#include <type_traits> +#include <string_view> + +#include <gsl/gsl-lite.hpp> + + +// Cf. https://docs.microsoft.com/en-us/cpp/code-quality/code-analysis-for-cpp-corecheck for a list of warnings in the MSVC +// C++ Core Guidelines Checker. + + +namespace { + +std::string_view get_string_view() noexcept { return "hi"; } +gsl::span<int const> get_span() noexcept { return { }; } +gsl_lite::span<int const> get_span2() noexcept { return { }; } +void get_span_ref() noexcept +{ + auto const & sv_ref = get_string_view(); // expect C26445 + std::ignore = sv_ref; + auto const & span_ref = get_span(); // expect C26445 + std::ignore = span_ref; + auto const & span2_ref = get_span2(); // expect C26445 + std::ignore = span2_ref; +} + +std::vector<int> get_vector(gsl::span<int const>) noexcept { return { }; } +void assign_temporary_span() noexcept +{ + auto span = get_span(); + span = get_vector(span); // expect C26449 +} + +void test_not_null_for_null() +{ + int i = 0; + gsl::not_null<int*> const pi(&i); + std::ignore = pi; + //std::ignore = pi == nullptr; // expect C26431 (does not compile for gsl-lite) + gsl_lite::not_null<int*> const pi2(&i); + std::ignore = pi2; + //std::ignore = pi2 == nullptr; // expect C26431 (does not compile for gsl-lite) +} + +int dereference(int const* pi) noexcept // expect C26429 +{ + return *pi; +} +int dereferenceNotNull(gsl::not_null<int const*> pi) +{ + return *pi; +} +int dereferenceNotNull2(gsl_lite::not_null<int const*> pi) +{ + return *pi; +} +int dereferenceNotNull3(int const* pi) +{ + Expects(pi != nullptr); + return *pi; +} + +int* newInt() noexcept { return nullptr; } +gsl::owner<int*> newIntOwner() noexcept { return nullptr; } +gsl_lite::owner<int*> newIntOwner2() noexcept { return nullptr; } +void newDelete() noexcept +{ + int* pi = newInt(); + [[gsl::suppress(r.11)]] delete pi; // expect C26401 + gsl::owner<int*> pi2 = newInt(); // expect C26406 + std::ignore = pi2; + gsl::owner<int*> pi3 = newIntOwner(); + [[gsl::suppress(r.11)]] delete pi3; + gsl_lite::owner<int*> pi4 = newIntOwner2(); + [[gsl::suppress(r.11)]] delete pi4; +} + +} // anonymous namespace + + +int main() noexcept +{ +} diff --git a/thirdparty/gsl-lite/test/core_check_lite.t.cpp b/thirdparty/gsl-lite/test/core_check_lite.t.cpp new file mode 100644 index 000000000..fde522f31 --- /dev/null +++ b/thirdparty/gsl-lite/test/core_check_lite.t.cpp @@ -0,0 +1,74 @@ + +#include <tuple> // for ignore +#include <vector> +#include <type_traits> +#include <string_view> + +#include <gsl-lite/gsl-lite.hpp> + + +// Cf. https://docs.microsoft.com/en-us/cpp/code-quality/code-analysis-for-cpp-corecheck for a list of warnings in the MSVC +// C++ Core Guidelines Checker. + + +namespace { + +std::string_view get_string_view() noexcept { return "hi"; } +gsl_lite::span<int const> get_span() noexcept { return { }; } +void get_span_ref() noexcept +{ + auto const & sv_ref = get_string_view(); // expect C26445 + std::ignore = sv_ref; + auto const & span_ref = get_span(); // expect C26445 + std::ignore = span_ref; +} + +std::vector<int> get_vector(gsl_lite::span<int const>) noexcept { return { }; } +void assign_temporary_span() noexcept +{ + auto span = get_span(); + span = get_vector(span); // expect C26449 +} + +void test_not_null_for_null() +{ + int i = 0; + gsl_lite::not_null<int*> const pi(&i); + std::ignore = pi; + //std::ignore = pi == nullptr; // expect C26431 (does not compile for gsl-lite) + gsl_lite::not_null<int*> const pi2(&i); + std::ignore = pi2; + //std::ignore = pi2 == nullptr; // expect C26431 (does not compile for gsl-lite) +} + +int dereference(int const* pi) noexcept // expect C26429 +{ + return *pi; +} +int dereferenceNotNull(gsl_lite::not_null<int const*> pi) +{ + return *pi; +} +int dereferenceNotNull2(gsl_lite::not_null<int const*> pi) +{ + return *pi; +} +int dereferenceNotNull3(int const* pi) +{ + Expects(pi != nullptr); + return *pi; +} + +int* newInt() noexcept { return nullptr; } +gsl_lite::owner<int*> newIntOwner() noexcept { return nullptr; } +void newDelete() noexcept +{ + int* pi = newInt(); + [[gsl::suppress(r.11)]] delete pi; // expect C26401 + gsl_lite::owner<int*> pi2 = newInt(); // expect C26406 + std::ignore = pi2; + gsl_lite::owner<int*> pi3 = newIntOwner(); + [[gsl::suppress(r.11)]] delete pi3; +} + +} // anonymous namespace diff --git a/thirdparty/gsl-lite/test/cuda/cuda.t.cu b/thirdparty/gsl-lite/test/cuda/cuda.t.cu new file mode 100644 index 000000000..0826a1f01 --- /dev/null +++ b/thirdparty/gsl-lite/test/cuda/cuda.t.cu @@ -0,0 +1,176 @@ +// +// gsl-lite is based on GSL: Guidelines Support Library. +// For more information see https://github.com/martinmoene/gsl-lite +// +// Copyright (c) 2015 Martin Moene +// Copyright (c) 2019-2025 Moritz Beutel +// Copyright (c) 2015 Microsoft Corporation. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "../gsl-lite.t.hpp" + +#include <memory> +#include <sstream> + + +// CUDA error checking macro borrowed from https://stackoverflow.com/a/14038590 and adapted. +#define myCudaErrchk(ans) ( myCudaErrchkImpl( (ans), #ans, __FILE__, __LINE__ ) ) +inline void myCudaErrchkImpl( cudaError_t code, char const * expr, char const * file, int line ) +{ + if ( code != cudaSuccess ) + { + std::ostringstream sstr; + sstr << "CUDA error in '" << expr << "' at " << file << "(" << line << "): " + << cudaGetErrorString( code ); + throw std::runtime_error( sstr.str() ); + } +} + + +struct CudaMallocDeleter +{ + template< class T > + void operator ()( T* data ) const + { + cudaFree( data ); + } +}; + +template< class T > +using CudaUniquePtr = std::unique_ptr<T, CudaMallocDeleter>; + +template< class T > +struct CudaAllocHelper +{ + static CudaUniquePtr<T> cudaAllocUnique() + { + T* ptr; + auto ec = cudaMalloc( &ptr, sizeof( T ) ); + if ( ec != cudaSuccess ) throw std::bad_alloc{ }; + return CudaUniquePtr<T>( ptr ); + } +}; +template< class T > +struct CudaAllocHelper<T[]> +{ + static CudaUniquePtr<T[]> cudaAllocUnique( std::size_t n ) + { + T* ptr; + auto ec = cudaMalloc( &ptr, sizeof( T ) * n ); + if ( ec != cudaSuccess ) throw std::bad_alloc{ }; + return CudaUniquePtr<T[]>( ptr ); + } +}; +template< class T > +CudaUniquePtr<T> cudaAllocUnique() +{ + return CudaAllocHelper<T>::cudaAllocUnique(); +} +template< class T > +CudaUniquePtr<T> cudaAllocUnique( std::size_t n ) +{ + return CudaAllocHelper<T>::cudaAllocUnique(n); +} + + +__global__ void preconditionAssertionKernel( int i, int j ) +{ + gsl_Expects( i >= 0 ); + gsl_ExpectsAudit( i < j ); + gsl_Ensures( i >= 0 ); + gsl_EnsuresAudit( i < j ); + gsl_Assert( i >= 0 ); + gsl_AssertAudit( i < j ); +} + +CASE( "CUDA: Precondition/postcondition checks and assertions can be used in kernel code" ) +{ + preconditionAssertionKernel<<<1, 1>>>( 0, 1 ); + myCudaErrchk( cudaPeekAtLastError() ); // check for invalid launch arguments + myCudaErrchk( cudaDeviceSynchronize() ); // check for execution errors +} + + +__global__ void spanKernel( gsl_lite::span< int > span ) +{ + int* data = span.data(); + gsl_CONFIG_SPAN_INDEX_TYPE size = span.size(); + if (size > 0) + { + span[0] = 42; + at( span, 0 ) = 42; + } +} + +CASE( "CUDA: span<> can be passed to kernel code" ) +{ + spanKernel<<<1, 1>>>( gsl_lite::span< int >( ) ); + myCudaErrchk( cudaPeekAtLastError() ); // check for invalid launch arguments + myCudaErrchk( cudaDeviceSynchronize() ); // check for execution errors +} + +CASE( "CUDA: span<> can be used in kernel code" ) +{ + std::size_t n = 3; + auto array = cudaAllocUnique<int[]>(n); + auto span = gsl_lite::make_span(array.get(), n); + spanKernel<<<1, 1>>>( span ); + myCudaErrchk( cudaPeekAtLastError() ); // check for invalid launch arguments + myCudaErrchk( cudaDeviceSynchronize() ); // check for execution errors +} + + +__global__ void notNullRawKernel( gsl_lite::not_null< int* > ptr ) +{ + *ptr = 1; + auto ptr2 = ptr; + *ptr2 = 2; + ptr = ptr2; +} + +// Not supported yet because `std::unique_ptr<>` member functions are neither `constexpr` nor `__host__ __device__`. +//__global__ void notNullUniqueKernel( gsl_lite::not_null< CudaUniquePtr< int > > ptr ) +//{ +// *ptr = 3; +// auto ptr2 = std::move( ptr ); +// *ptr2 = 4; +// ptr = std::move( ptr2 ); +//} + +CASE( "CUDA: not_null<> can be passed to and used in kernel code" ) +{ + auto pi = cudaAllocUnique<int>(); + + notNullRawKernel<<<1, 1>>>( gsl_lite::make_not_null( pi.get() ) ); + myCudaErrchk( cudaPeekAtLastError() ); // check for invalid launch arguments + myCudaErrchk( cudaDeviceSynchronize() ); // check for execution errors + + //notNullUniqueKernel<<<1, 1>>>( gsl_lite::make_not_null( std::move( pi ) ) ); + //myCudaErrchk( cudaPeekAtLastError() ); // check for invalid launch arguments + //myCudaErrchk( cudaDeviceSynchronize() ); // check for execution errors +} + + +__global__ void failFastKernel() +{ + gsl_FailFast(); +} + +CASE( "CUDA: gsl_FailFast() can be used in kernel code" ) +{ + failFastKernel<<<1, 1>>>(); + myCudaErrchk( cudaPeekAtLastError() ); + EXPECT( cudaDeviceSynchronize() != cudaSuccess ); + // Note that executing a trap instruction or an assertion in a CUDA kernel destroys the context, so this should be + // the last test case we execute. +} + diff --git a/thirdparty/gsl-lite/test/emulation.t.cpp b/thirdparty/gsl-lite/test/emulation.t.cpp new file mode 100644 index 000000000..8d9ec4445 --- /dev/null +++ b/thirdparty/gsl-lite/test/emulation.t.cpp @@ -0,0 +1,121 @@ +// +// gsl-lite is based on GSL: Guidelines Support Library. +// For more information see https://github.com/gsl-lite/gsl-lite +// +// Copyright (c) 2015-2019 Martin Moene +// Copyright (c) 2019-2021 Moritz Beutel +// Copyright (c) 2015-2018 Microsoft Corporation. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +#include "gsl-lite.t.hpp" + +using namespace gsl_lite; + + +#if gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( VARIADIC_TEMPLATE ) +template <int> struct True : std::true_type { }; +template <int> struct False : std::false_type { }; + +struct Incomplete; +#endif // gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( VARIADIC_TEMPLATE ) + + +#if gsl_FEATURE( STRING_SPAN ) || gsl_CONFIG( ALLOWS_SPAN_COMPARISON ) +CASE( "equal()" ) +{ + char const* arg1 = "foo"; + char const* arg2 = "fou"; + EXPECT( detail::equal( arg1, arg1 + std::strlen( arg1 ), arg1 ) ); + EXPECT( ! detail::equal( arg1, arg1 + std::strlen( arg1 ), arg2 ) ); + EXPECT( ! detail::equal( arg2, arg2 + std::strlen( arg2 ), arg1 ) ); + + std::istringstream sstr1a1( "foo" ), sstr1a2( "foo" ), sstr1b( "foo" ), sstr1c( "foo" ); + std::istringstream sstr2b( "fou" ), sstr2c( "fou" ); + EXPECT( detail::equal( std::istreambuf_iterator<char>( sstr1a1 ), std::istreambuf_iterator<char>(), std::istreambuf_iterator<char>( sstr1a2 ) ) ); + EXPECT( ! detail::equal( std::istreambuf_iterator<char>( sstr1b ), std::istreambuf_iterator<char>(), std::istreambuf_iterator<char>( sstr2b ) ) ); + EXPECT( ! detail::equal( std::istreambuf_iterator<char>( sstr2c ), std::istreambuf_iterator<char>(), std::istreambuf_iterator<char>( sstr1c ) ) ); +} + +template < typename T, std::size_t N > +std::size_t arraySize( T (&)[N] ) +{ + return N; +} + +CASE( "lexicographical_compare()" ) +{ + std::pair<char const*, char const*> less[] = { + std::make_pair("", "foo"), + std::make_pair("fa", "foo"), + std::make_pair("foe", "foo"), + std::make_pair("fond", "foo") + }; + for ( std::size_t i = 0, n = arraySize( less ); i != n; ++i ) + { + EXPECT( detail::lexicographical_compare( less[i].first, less[i].first + std::strlen( less[i].first ), less[i].second, less[i].second + std::strlen( less[i].second ) )); + + std::istringstream sstr1( less[i].first ); + std::istringstream sstr2( less[i].second ); + std::istreambuf_iterator<char> it1( sstr1 ), it1End; + std::istreambuf_iterator<char> it2( sstr2 ), it2End; + EXPECT( detail::lexicographical_compare( it1, it1End, it2, it2End )); + } + + std::pair<char const*, char const*> notLess[] = { + std::make_pair("g", "foo"), + std::make_pair("fu", "foo"), + std::make_pair("foo", "foo"), + std::make_pair("fou", "foo"), + std::make_pair("fool", "foo"), + std::make_pair("foul", "foo") + }; + for ( std::size_t i = 0, n = arraySize( less ); i != n; ++i ) + { + EXPECT( ! detail::lexicographical_compare( notLess[i].first, notLess[i].first + std::strlen( notLess[i].first ), notLess[i].second, notLess[i].second + std::strlen( notLess[i].second ) )); + + std::istringstream sstr1( notLess[i].first ); + std::istringstream sstr2( notLess[i].second ); + std::istreambuf_iterator<char> it1( sstr1 ), it1End; + std::istreambuf_iterator<char> it2( sstr2 ), it2End; + EXPECT( ! detail::lexicographical_compare( it1, it1End, it2, it2End )); + } +} +#endif // gsl_FEATURE( STRING_SPAN ) || gsl_CONFIG( ALLOWS_SPAN_COMPARISON ) + +CASE( "conjunction<> and disjunction<>: Short-circuiting is handled correctly" ) +{ +#if gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( VARIADIC_TEMPLATE ) + static_assert(std::is_base_of<True<0>, std17::disjunction<True<0>, Incomplete>>::value, "static assertion failed"); + static_assert(std::is_base_of<False<0>, std17::conjunction<False<0>, Incomplete>>::value, "static assertion failed"); +#endif // gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( VARIADIC_TEMPLATE ) +} + +CASE( "conjunction<> and disjunction<>: First suitable type is chosen as base" ) +{ +#if gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( VARIADIC_TEMPLATE ) + static_assert(std::is_base_of<std::false_type, std17::disjunction<>>::value, "static assertion failed"); + static_assert(std::is_base_of<True<0>, std17::disjunction<True<0>>>::value, "static assertion failed"); + static_assert(std::is_base_of<False<0>, std17::disjunction<False<0>>>::value, "static assertion failed"); + static_assert(std::is_base_of<True<0>, std17::disjunction<True<0>, True<1>>>::value, "static assertion failed"); + static_assert(std::is_base_of<True<0>, std17::disjunction<True<0>, True<1>, True<2>>>::value, "static assertion failed"); + static_assert(std::is_base_of<True<1>, std17::disjunction<False<0>, True<1>, True<2>>>::value, "static assertion failed"); + static_assert(std::is_base_of<False<2>, std17::disjunction<False<0>, False<1>, False<2>>>::value, "static assertion failed"); + static_assert(std::is_base_of<std::true_type, std17::conjunction<>>::value, "static assertion failed"); + static_assert(std::is_base_of<True<0>, std17::conjunction<True<0>>>::value, "static assertion failed"); + static_assert(std::is_base_of<False<0>, std17::conjunction<False<0>>>::value, "static assertion failed"); + static_assert(std::is_base_of<True<1>, std17::conjunction<True<0>, True<1>>>::value, "static assertion failed"); + static_assert(std::is_base_of<True<2>, std17::conjunction<True<0>, True<1>, True<2>>>::value, "static assertion failed"); + static_assert(std::is_base_of<False<1>, std17::conjunction<True<0>, False<1>, False<2>>>::value, "static assertion failed"); + static_assert(std::is_base_of<False<0>, std17::conjunction<False<0>, False<1>, False<2>>>::value, "static assertion failed"); +#endif // gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( VARIADIC_TEMPLATE ) +} diff --git a/thirdparty/gsl-lite/test/gsl-lite.t.cpp b/thirdparty/gsl-lite/test/gsl-lite.t.cpp new file mode 100644 index 000000000..24346989f --- /dev/null +++ b/thirdparty/gsl-lite/test/gsl-lite.t.cpp @@ -0,0 +1,298 @@ +// Copyright (c) 2015-2019 Martin Moene +// Copyright (c) 2019-2021 Moritz Beutel +// Copyright (c) 2015-2018 Microsoft Corporation. All rights reserved. +// +// gsl-lite is based on GSL: Guidelines Support Library. +// For more information see https://github.com/gsl-lite/gsl-lite +// +// This code is licensed under the MIT License (MIT). +// + +#include "gsl-lite.t.hpp" + +#define gsl_PRINT_NUMERIC( x ) \ + std::cout << #x << ": " << x << "\n" + +#define gsl_PRINT_BOOLEAN( x ) \ + std::cout << #x << ": " << x << "\n" + +#define gsl_PRINT_TOKEN( x ) \ + std::cout << #x << ": " << gsl_STRINGIFY(x) << "\n" + +#define gsl_PRESENT( x ) \ + std::cout << #x << ": (defined)" << "\n" + +#define gsl_ABSENT( x ) \ + std::cout << #x << ": (undefined)\n" + +#define gsl_PRINT_NO_VALUE( x ) \ + std::cout << #x << ": (no value)\n" + +lest::tests & specification() +{ + static lest::tests tests; + return tests; +} + +CASE( "gsl-lite version" "[.version]" ) +{ + gsl_PRINT_NUMERIC( gsl_lite_VERSION ); +} + +CASE( "C++ compiler: compiler version" "[.compiler]" ) +{ + gsl_PRINT_NUMERIC( gsl_COMPILER_APPLECLANG_VERSION ); + gsl_PRINT_NUMERIC( gsl_COMPILER_CLANG_VERSION ); + gsl_PRINT_NUMERIC( gsl_COMPILER_GNUC_VERSION ); + gsl_PRINT_NUMERIC( gsl_COMPILER_MSVC_VERSION ); +} + +CASE( "__cplusplus" "[.stdc++]" ) +{ + gsl_PRINT_NUMERIC( __cplusplus ); + gsl_PRINT_NUMERIC( gsl_CPLUSPLUS ); +} + +CASE( "_MSVC_LANG" "[.stdc++]" ) +{ +#ifdef _MSVC_LANG + gsl_PRINT_NUMERIC( _MSVC_LANG ); +#else + gsl_ABSENT( _MSVC_LANG ); +#endif +} + +CASE( "gsl_CPP11_OR_GREATER" "[.stdc++]" ) +{ + gsl_PRINT_BOOLEAN( gsl_CPP11_OR_GREATER ); +} + +CASE( "gsl_CPP14_OR_GREATER" "[.stdc++]" ) +{ + gsl_PRINT_BOOLEAN( gsl_CPP14_OR_GREATER ); +} + +CASE( "gsl_CPP17_OR_GREATER" "[.stdc++]" ) +{ + gsl_PRINT_BOOLEAN( gsl_CPP17_OR_GREATER ); +} + +CASE( "gsl_CPP20_OR_GREATER" "[.stdc++]" ) +{ + gsl_PRINT_BOOLEAN( gsl_CPP20_OR_GREATER ); +} + +CASE( "gsl_STDLIB_CPP11_OR_GREATER" "[.stdc++]" ) +{ + gsl_PRINT_BOOLEAN( gsl_STDLIB_CPP11_OR_GREATER ); +} + +CASE( "gsl_STDLIB_CPP14_OR_GREATER" "[.stdc++]" ) +{ + gsl_PRINT_BOOLEAN( gsl_STDLIB_CPP14_OR_GREATER ); +} + +CASE( "gsl_STDLIB_CPP17_OR_GREATER" "[.stdc++]" ) +{ + gsl_PRINT_BOOLEAN( gsl_STDLIB_CPP17_OR_GREATER ); +} + +CASE( "gsl_STDLIB_CPP20_OR_GREATER" "[.stdc++]" ) +{ + gsl_PRINT_BOOLEAN( gsl_STDLIB_CPP20_OR_GREATER ); +} + +CASE( "Presence of C++ language features" "[.stdlanguage]" ) +{ + gsl_PRINT_BOOLEAN( gsl_HAVE( ALIAS_TEMPLATE ) ); + gsl_PRINT_BOOLEAN( gsl_HAVE( AUTO ) ); + gsl_PRINT_BOOLEAN( gsl_HAVE( CONSTEXPR_11 ) ); + gsl_PRINT_BOOLEAN( gsl_HAVE( CONSTEXPR_14 ) ); + gsl_PRINT_BOOLEAN( gsl_HAVE( CONSTEXPR_17 ) ); + gsl_PRINT_BOOLEAN( gsl_HAVE( CONSTEXPR_20 ) ); + gsl_PRINT_BOOLEAN( gsl_HAVE( DECLTYPE_AUTO ) ); + gsl_PRINT_BOOLEAN( gsl_HAVE( DEDUCTION_GUIDES ) ); + gsl_PRINT_BOOLEAN( gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) ); + gsl_PRINT_BOOLEAN( gsl_HAVE( DEPRECATED ) ); + gsl_PRINT_BOOLEAN( gsl_HAVE( ENUM_CLASS ) ); + gsl_PRINT_BOOLEAN( gsl_HAVE( ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE ) ); + gsl_PRINT_BOOLEAN( gsl_HAVE( EXCEPTIONS ) ); + gsl_PRINT_BOOLEAN( gsl_HAVE( EXPLICIT ) ); + gsl_PRINT_BOOLEAN( gsl_HAVE( EXPRESSION_SFINAE ) ); + gsl_PRINT_BOOLEAN( gsl_HAVE( FUNCTION_REF_QUALIFIER ) ); + gsl_PRINT_BOOLEAN( gsl_HAVE( INITIALIZER_LIST ) ); + gsl_PRINT_BOOLEAN( gsl_HAVE( IS_DEFAULT ) ); + gsl_PRINT_BOOLEAN( gsl_HAVE( IS_DELETE ) ); + gsl_PRINT_BOOLEAN( gsl_HAVE( NODISCARD ) ); + gsl_PRINT_BOOLEAN( gsl_HAVE( NOEXCEPT ) ); + gsl_PRINT_BOOLEAN( gsl_HAVE( NORETURN ) ); + gsl_PRINT_BOOLEAN( gsl_HAVE( NULLPTR ) ); + gsl_PRINT_BOOLEAN( gsl_HAVE( RVALUE_REFERENCE ) ); + gsl_PRINT_BOOLEAN( gsl_HAVE( VARIADIC_TEMPLATE ) ); + gsl_PRINT_BOOLEAN( gsl_HAVE( WCHAR ) ); +} + +CASE( "Presence of C++ library features" "[.stdlibrary]" ) +{ + gsl_PRINT_BOOLEAN( gsl_HAVE( ADD_CONST ) ); + gsl_PRINT_BOOLEAN( gsl_HAVE( ADDRESSOF ) ); + gsl_PRINT_BOOLEAN( gsl_HAVE( ARRAY ) ); + gsl_PRINT_BOOLEAN( gsl_HAVE( CONTAINER_DATA_METHOD ) ); + gsl_PRINT_BOOLEAN( gsl_HAVE( INTEGRAL_CONSTANT ) ); + gsl_PRINT_BOOLEAN( gsl_HAVE( HASH ) ); + gsl_PRINT_BOOLEAN( gsl_HAVE( MAKE_SHARED ) ); + gsl_PRINT_BOOLEAN( gsl_HAVE( MAKE_UNIQUE ) ); + gsl_PRINT_BOOLEAN( gsl_HAVE( MOVE_FORWARD ) ); + gsl_PRINT_BOOLEAN( gsl_HAVE( REMOVE_CONST ) ); + gsl_PRINT_BOOLEAN( gsl_HAVE( REMOVE_CVREF ) ); + gsl_PRINT_BOOLEAN( gsl_HAVE( REMOVE_REFERENCE ) ); + gsl_PRINT_BOOLEAN( gsl_HAVE( SHARED_PTR ) ); + gsl_PRINT_BOOLEAN( gsl_HAVE( SIZED_TYPES ) ); + gsl_PRINT_BOOLEAN( gsl_HAVE( STD_DATA ) ); + gsl_PRINT_BOOLEAN( gsl_HAVE( TR1_ADD_CONST ) ); + gsl_PRINT_BOOLEAN( gsl_HAVE( TR1_INTEGRAL_CONSTANT ) ); + gsl_PRINT_BOOLEAN( gsl_HAVE( TR1_REMOVE_CONST ) ); + gsl_PRINT_BOOLEAN( gsl_HAVE( TR1_REMOVE_REFERENCE ) ); + gsl_PRINT_BOOLEAN( gsl_HAVE( TR1_TYPE_TRAITS ) ); + gsl_PRINT_BOOLEAN( gsl_HAVE( TYPE_TRAITS ) ); + gsl_PRINT_BOOLEAN( gsl_HAVE( UNCAUGHT_EXCEPTIONS ) ); + gsl_PRINT_BOOLEAN( gsl_HAVE( UNIQUE_PTR ) ); + +#ifdef _HAS_CPP0X + gsl_PRINT_BOOLEAN( _HAS_CPP0X ); +#else + gsl_ABSENT( _HAS_CPP0X ); +#endif +} + +CASE( "gsl-lite configuration" "[.gsl-configuration]" ) +{ +//#if gsl_CHECK_CFG_NO_VALUE_( gsl_api ) +// gsl_PRINT_NO_VALUE( gsl_api ); +//#else +// gsl_PRINT_TOKEN( gsl_api ); +//#endif + +#ifdef gsl_CONFIG_CONTRACT_CHECKING_AUDIT + gsl_PRESENT( gsl_CONFIG_CONTRACT_CHECKING_AUDIT ); +#else + gsl_ABSENT( gsl_CONFIG_CONTRACT_CHECKING_AUDIT ); +#endif + +#ifdef gsl_CONFIG_CONTRACT_CHECKING_ON + gsl_PRESENT( gsl_CONFIG_CONTRACT_CHECKING_ON ); +#else + gsl_ABSENT( gsl_CONFIG_CONTRACT_CHECKING_ON ); +#endif + +#ifdef gsl_CONFIG_CONTRACT_CHECKING_OFF + gsl_PRESENT( gsl_CONFIG_CONTRACT_CHECKING_OFF ); +#else + gsl_ABSENT( gsl_CONFIG_CONTRACT_CHECKING_OFF ); +#endif + +#ifdef gsl_CONFIG_CONTRACT_CHECKING_ENSURES_OFF + gsl_PRESENT( gsl_CONFIG_CONTRACT_CHECKING_ENSURES_OFF ); +#else + gsl_ABSENT( gsl_CONFIG_CONTRACT_CHECKING_ENSURES_OFF ); +#endif + +#ifdef gsl_CONFIG_CONTRACT_CHECKING_EXPECTS_OFF + gsl_PRESENT( gsl_CONFIG_CONTRACT_CHECKING_EXPECTS_OFF ); +#else + gsl_ABSENT( gsl_CONFIG_CONTRACT_CHECKING_EXPECTS_OFF ); +#endif + +#ifdef gsl_CONFIG_UNENFORCED_CONTRACTS_ASSUME + gsl_PRESENT( gsl_CONFIG_UNENFORCED_CONTRACTS_ASSUME ); +#else + gsl_ABSENT( gsl_CONFIG_UNENFORCED_CONTRACTS_ASSUME ); +#endif + +#ifdef gsl_CONFIG_UNENFORCED_CONTRACTS_ELIDE + gsl_PRESENT( gsl_CONFIG_UNENFORCED_CONTRACTS_ELIDE ); +#else + gsl_ABSENT( gsl_CONFIG_UNENFORCED_CONTRACTS_ELIDE ); +#endif + +#ifdef gsl_CONFIG_CONTRACT_VIOLATION_TERMINATES + gsl_PRESENT( gsl_CONFIG_CONTRACT_VIOLATION_TERMINATES ); +#else + gsl_ABSENT( gsl_CONFIG_CONTRACT_VIOLATION_TERMINATES ); +#endif + +#ifdef gsl_CONFIG_CONTRACT_VIOLATION_THROWS + gsl_PRESENT( gsl_CONFIG_CONTRACT_VIOLATION_THROWS ); +#else + gsl_ABSENT( gsl_CONFIG_CONTRACT_VIOLATION_THROWS ); +#endif + +#ifdef gsl_CONFIG_CONTRACT_VIOLATION_CALLS_HANDLER + gsl_PRESENT( gsl_CONFIG_CONTRACT_VIOLATION_CALLS_HANDLER ); +#else + gsl_ABSENT( gsl_CONFIG_CONTRACT_VIOLATION_CALLS_HANDLER ); +#endif + + gsl_PRINT_BOOLEAN( gsl_CONFIG( TRANSPARENT_NOT_NULL ) ); + gsl_PRINT_BOOLEAN( gsl_CONFIG_DEPRECATE_TO_LEVEL ); + gsl_PRINT_TOKEN( gsl_CONFIG( SPAN_INDEX_TYPE ) ); + gsl_PRINT_TOKEN( gsl_CONFIG( INDEX_TYPE ) ); + gsl_PRINT_BOOLEAN( gsl_CONFIG( NOT_NULL_EXPLICIT_CTOR ) ); + gsl_PRINT_BOOLEAN( gsl_CONFIG( NOT_NULL_GET_BY_CONST_REF ) ); + gsl_PRINT_BOOLEAN( gsl_CONFIG( CONFIRMS_COMPILATION_ERRORS ) ); + gsl_PRINT_BOOLEAN( gsl_CONFIG( ALLOWS_SPAN_COMPARISON ) ); + gsl_PRINT_BOOLEAN( gsl_CONFIG( ALLOWS_NONSTRICT_SPAN_COMPARISON ) ); + gsl_PRINT_BOOLEAN( gsl_CONFIG( ALLOWS_UNCONSTRAINED_SPAN_CONTAINER_CTOR ) ); + gsl_PRINT_BOOLEAN( gsl_CONFIG( NARROW_THROWS_ON_TRUNCATION ) ); +} + +CASE( "gsl-lite features" "[.gsl-features]" ) +{ + gsl_PRINT_BOOLEAN( gsl_FEATURE( WITH_CONTAINER_TO_STD ) ); + gsl_PRINT_BOOLEAN( gsl_FEATURE( MAKE_SPAN_TO_STD ) ); + gsl_PRINT_BOOLEAN( gsl_FEATURE( BYTE_SPAN_TO_STD ) ); + gsl_PRINT_BOOLEAN( gsl_FEATURE( IMPLICIT_MACRO ) ); + gsl_PRINT_BOOLEAN( gsl_FEATURE( OWNER_MACRO ) ); + gsl_PRINT_BOOLEAN( gsl_FEATURE( EXPERIMENTAL_RETURN_GUARD ) ); + gsl_PRINT_BOOLEAN( gsl_FEATURE( GSL_LITE_NAMESPACE ) ); +} + +int main( int argc, char * argv[] ) +{ + // We only run tests for targets with exceptions enabled. lest has been modified to permit compilation without exceptions + // so we can test compiling gsl-lite without exceptions, but the no-exception tests will not run correctly because lest + // relies on exceptions for running tests and therefore cannot function correctly without. + if ( ! gsl_HAVE( EXCEPTIONS ) ) + { + std::cerr << "Cannot run test suite with exceptions disabled; exiting.\n"; + return 1; + } + + return lest::run( specification(), argc, argv ); +} + +#if defined( gsl_CONFIG_CONTRACT_VIOLATION_CALLS_HANDLER ) +namespace gsl_lite { + +gsl_api void fail_fast_assert_handler( char const * const expression, char const * const message, char const * const file, int line ) +{ + std::cerr << message << ": " << expression << " at " << file << ":" << line << "\n"; +} + +} // namespace gsl_lite +#endif + +#if 0 +g++ -I../include/gsl -Dgsl_CONFIG_CONTRACT_VIOLATION_THROWS -o gsl-lite.t.exe gsl-lite.t.cpp assert.t.cpp at.t.cpp byte.t.cpp issue.t.cpp not_null.t.cpp owner.t.cpp span.t.cpp string_span.t.cpp util.t.cpp && gsl-lite.t.exe --pass +g++ -std=c++98 -I../include/gsl -Dgsl_CONFIG_CONTRACT_VIOLATION_THROWS -o gsl-lite.t.exe gsl-lite.t.cpp assert.t.cpp at.t.cpp byte.t.cpp issue.t.cpp not_null.t.cpp owner.t.cpp span.t.cpp string_span.t.cpp util.t.cpp && gsl-lite.t.exe --pass +g++ -std=c++03 -I../include/gsl -Dgsl_CONFIG_CONTRACT_VIOLATION_THROWS -o gsl-lite.t.exe gsl-lite.t.cpp assert.t.cpp at.t.cpp byte.t.cpp issue.t.cpp not_null.t.cpp owner.t.cpp span.t.cpp string_span.t.cpp util.t.cpp && gsl-lite.t.exe --pass +g++ -std=c++0x -I../include/gsl -Dgsl_CONFIG_CONTRACT_VIOLATION_THROWS -o gsl-lite.t.exe gsl-lite.t.cpp assert.t.cpp at.t.cpp byte.t.cpp issue.t.cpp not_null.t.cpp owner.t.cpp span.t.cpp string_span.t.cpp util.t.cpp && gsl-lite.t.exe --pass +g++ -std=c++11 -I../include/gsl -Dgsl_CONFIG_CONTRACT_VIOLATION_THROWS -o gsl-lite.t.exe gsl-lite.t.cpp assert.t.cpp at.t.cpp byte.t.cpp issue.t.cpp not_null.t.cpp owner.t.cpp span.t.cpp string_span.t.cpp util.t.cpp && gsl-lite.t.exe --pass +g++ -std=c++14 -I../include/gsl -Dgsl_CONFIG_CONTRACT_VIOLATION_THROWS -o gsl-lite.t.exe gsl-lite.t.cpp assert.t.cpp at.t.cpp byte.t.cpp issue.t.cpp not_null.t.cpp owner.t.cpp span.t.cpp string_span.t.cpp util.t.cpp && gsl-lite.t.exe --pass + +cl -EHsc -I../include/gsl -Dgsl_CONFIG_CONTRACT_VIOLATION_THROWS gsl-lite.t.cpp assert.t.cpp at.t.cpp byte.t.cpp issue.t.cpp not_null.t.cpp owner.t.cpp span.t.cpp string_span.t.cpp util.t.cpp && gsl-lite.t.exe --pass + +cl -EHsc -I../include/gsl -Dgsl_CONFIG_CONTRACT_VIOLATION_THROWS -Dgsl_CONFIG_CONFIRMS_COMPILATION_ERRORS gsl-lite.t.cpp assert.t.cpp at.t.cpp byte.t.cpp issue.t.cpp not_null.t.cpp owner.t.cpp span.t.cpp string_span.t.cpp util.t.cpp && gsl-lite.t.exe --pass +#endif + +// end of file diff --git a/thirdparty/gsl-lite/test/gsl-lite.t.hpp b/thirdparty/gsl-lite/test/gsl-lite.t.hpp new file mode 100644 index 000000000..aeb2271ef --- /dev/null +++ b/thirdparty/gsl-lite/test/gsl-lite.t.hpp @@ -0,0 +1,149 @@ +// Copyright (c) 2015-2019 Martin Moene +// Copyright (c) 2019-2021 Moritz Beutel +// Copyright (c) 2015-2018 Microsoft Corporation. All rights reserved. +// +// gsl-lite is based on GSL: Guidelines Support Library. +// For more information see https://github.com/gsl-lite/gsl-lite +// +// This code is licensed under the MIT License (MIT). +// + +#ifndef GSL_TEST_GSL_LITE_HPP_INCLUDED +#define GSL_TEST_GSL_LITE_HPP_INCLUDED + + +#include "gsl-lite/gsl-lite.hpp" + + +// gsl-lite only depends on <ios>, but we're instantiating templates using streams, so we need <ostream>. +#include <ostream> + +// Some test cases use stringstreams and other iostream functionality. +#include <sstream> +#include <iostream> + +// Additional general requirements. +#include <cstring> + + +// Limit C++ Core Guidelines checking to GSL Lite: + +#ifdef gsl_TESTING_CPPCORECHECK_ +# include <CppCoreCheck/warnings.h> +# pragma warning(disable: ALL_CPPCORECHECK_WARNINGS) +#endif + +// Compiler warning suppression for usage of lest: + +#ifdef __clang__ +# pragma clang diagnostic ignored "-Wunknown-pragmas" // don't warn if any of the following warnings are introduced later than the current compiler version +# pragma clang diagnostic ignored "-Wunknown-warning-option" // see above, but for newer compilers +# pragma clang diagnostic ignored "-Wstring-conversion" +# pragma clang diagnostic ignored "-Wunused-parameter" +# pragma clang diagnostic ignored "-Wunused-template" +# pragma clang diagnostic ignored "-Wunused-function" +# pragma clang diagnostic ignored "-Wunused-member-function" +# pragma clang diagnostic warning "-Wunknown-warning-option" // we want to see warnings about unknown warning options +# pragma clang diagnostic warning "-Wunknown-pragmas" // we want to see warnings about unknown pragmas +# pragma GCC diagnostic ignored "-Wweak-vtables" +#elif defined( __GNUC__ ) +# pragma GCC diagnostic ignored "-Wunused-parameter" +# pragma GCC diagnostic ignored "-Wunused-function" +# pragma GCC diagnostic ignored "-Wuseless-cast" +#elif defined( _MSC_VER ) +# if gsl_BETWEEN(gsl_COMPILER_MSVC_VERSION, 1, 140) +# pragma warning( disable : 4702 ) // unreachable code +# pragma warning( disable : 4512 ) // assignment operator could not be generated +# endif // gsl_BETWEEN(gsl_COMPILER_MSVC_VERSION, 1, 140) +# if gsl_BETWEEN(gsl_COMPILER_MSVC_VERSION, 1, 142) || !gsl_CPP17_OR_GREATER +# pragma warning( disable : 4100 ) // unreferenced formal parameter +# endif // !__has_cpp_attribute(maybe_unused) || !gsl_CPP17_OR_GREATER +#endif + + +namespace lest { + +// These functions cannot be found via ADL, so we have to define them before including lest. + +#if gsl_HAVE( ARRAY ) +template< typename T, std::size_t N > +inline std::ostream & operator<<( std::ostream & os, std::array<T,N> const & ) +{ + return os << std::hex << "[std::array[" << N << "]"; +} +#endif + +#if gsl_HAVE( WCHAR ) +// We do this with a loop and explicit casts to avoid warnings about implicit narrowing casts (which we don't care about because we don't have to handle non-ASCII strings in the tests). +inline std::string narrowString( std::wstring const & str ) +{ + std::string result(str.size(), '\0'); + for (std::size_t i = 0, n = str.size(); i != n; ++i) + { + result[i] = static_cast<char>(str[i]); + } + return result; +} + +inline std::ostream & operator<<( std::ostream & os, std::wstring const & text ) +{ + return os << narrowString( text ); +} +#endif // gsl_HAVE( WCHAR ) + +} // namespace lest + +#include "lest_cpp03.hpp" + +#define CASE( name ) lest_CASE( specification(), name ) + +extern lest::tests & specification(); + +namespace gsl_lite { + +inline const void * nullptr_void() { return gsl_nullptr; } + +// use operator<< instead of to_string() overload; +// see http://stackoverflow.com/a/10651752/437272 + +#if gsl_FEATURE( BYTE ) +inline std::ostream & operator<<( std::ostream & os, byte b ) +{ + return os << std::hex << "0x" << to_integer<int>(b); +} +#endif // gsl_FEATURE( BYTE ) + +template< typename T, gsl_CONFIG_SPAN_INDEX_TYPE Extent > +inline std::ostream & operator<<( std::ostream & os, span< T, Extent > s ) +{ + return os << "[", std::copy( s.begin(), s.end(), std::ostream_iterator<T>(os, ",") ), os << "]"; +} + +namespace detail { + +template< typename T > +inline std::ostream & operator<<( std::ostream & os, span_iterator< T > s ) +{ + return os << s.current_; +} + +template< typename T > +inline std::ostream & operator<<( std::ostream & os, std::reverse_iterator< span_iterator< T > > s ) +{ + return os << s.base().current_; +} + +} // namespace detail + +} // namespace gsl_lite + +# if gsl_FEATURE( STRING_SPAN ) +inline void suppress_warning_unused_template_ensure_sentinel() +{ + (void) gsl_lite::ensure_z( "zero-terminated" ); +} +# endif // gsl_FEATURE( STRING_SPAN ) + +#endif // GSL_TEST_GSL_LITE_HPP_INCLUDED + +// end of file diff --git a/thirdparty/gsl-lite/test/issue.t.cpp b/thirdparty/gsl-lite/test/issue.t.cpp new file mode 100644 index 000000000..aa0cd9b7c --- /dev/null +++ b/thirdparty/gsl-lite/test/issue.t.cpp @@ -0,0 +1,140 @@ +// +// gsl-lite is based on GSL: Guidelines Support Library. +// For more information see https://github.com/gsl-lite/gsl-lite +// +// Copyright (c) 2015-2019 Martin Moene +// Copyright (c) 2019-2021 Moritz Beutel +// Copyright (c) 2015-2018 Microsoft Corporation. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "gsl-lite.t.hpp" + +using namespace gsl_lite; + +CASE( "span<>: free comparation functions fail for different const-ness [issue #32]" ) +{ +#if gsl_FEATURE( STRING_SPAN ) +# if gsl_FEATURE_TO_STD( MAKE_SPAN ) +# if gsl_CONFIG( ALLOWS_NONSTRICT_SPAN_COMPARISON ) + char data[] = { 'a', 'b' }; + string_span a = make_span( data ); + cstring_span b = make_span( data ).last( 1 ); + + // worked as expected before 0.9.0, in 0.9.[0,1] converts to bool and compares equal! + + EXPECT( a != b ); +# else + EXPECT( !!"span<>: cannot compare different types (gsl_CONFIG_ALLOWS_NONSTRICT_SPAN_COMPARISON=0)" ); +# endif +# else + EXPECT( !!"span<>: make_span() is not available (gsl_FEATURE_MAKE_SPAN_TO_STD)" ); +# endif +#endif // gsl_FEATURE( STRING_SPAN ) +} + +CASE( "span<>: constrained container constructor suffers hard failure for arguments with reference-returning data() function [issue #242]" ) +{ +#if gsl_FEATURE( BYTE )&& gsl_HAVE( CONSTRAINED_SPAN_CONTAINER_CTOR ) && gsl_HAVE( TYPE_TRAITS ) + struct S + { + int data_{ }; + + explicit S( gsl_lite::span<gsl_lite::byte const> ) { } + int const & data() const { return data_; } + }; + + // S is not a `contiguous_range`, hence the range constructor should not be instantiable, but this needs to be a substitution + // failure, not a hard error. + EXPECT( !(std::is_constructible< gsl_lite::span< gsl_lite::byte const >, S >::value) ); +#else + EXPECT( !!"span<>: constrained container constructor is not available (gsl_HAVE_CONSTRAINED_SPAN_CONTAINER_CTOR=0)" ); +#endif +} + +#if gsl_COMPILER_MSVC_VERSION +# pragma warning( push ) +# pragma warning( disable : 4127 ) // conditional expression is constant +#endif + +CASE( "byte: aliasing rules lead to undefined behaviour when using enum class [issue #34](GSL issue #313, PR #390)" ) +{ +#if gsl_FEATURE( BYTE ) && gsl_HAVE( ENUM_CLASS ) + struct F { + static int f( int & i, gsl_lite::byte & r ) + { + i = 7; + r <<= 1; + return i; + } + }; + + int i = 0; + if ( std20::endian::native == std20::endian::little ) + { + EXPECT( 14 == F::f( i, reinterpret_cast<gsl_lite::byte*>( &i )[0] ) ); + } + else if ( std20::endian::native == std20::endian::big ) + { + EXPECT( 14 == F::f( i, reinterpret_cast<gsl_lite::byte*>( &i )[sizeof i - 1] ) ); + } +#endif // gsl_FEATURE( BYTE ) && gsl_HAVE( ENUM_CLASS ) +} + +#if gsl_COMPILER_MSVC_VERSION +# pragma warning( pop ) +#endif + +CASE( "string_span<>: must not include terminating '\\0' [issue #53]" ) +{ +#if gsl_FEATURE( STRING_SPAN ) + char const data[] = "ab"; + char const * text = "ab"; + cstring_span span = "ab"; + + cstring_span a( data ); + cstring_span b( ensure_z( text ) ); + + // may include terminating '\0' + // works differently from M-GSL and basic_string_span proposal: + + EXPECT( span.length() == 2u ); + EXPECT( a.length() == 2u ); + EXPECT( b.length() == 2u ); + + EXPECT( a == span ); + EXPECT( a == b ); +#endif // gsl_FEATURE( STRING_SPAN ) +} + +CASE( "string_span<>: to_string triggers SFINAE errors on basic_string_span's move & copy constructor with Clang-3.9 (define gsl_CONFIG_CONFIRMS_COMPILATION_ERRORS) [issue #53a]" ) +{ +# if gsl_FEATURE( STRING_SPAN ) && gsl_CONFIG( CONFIRMS_COMPILATION_ERRORS ) + cstring_span span = "Hello world"; + std::string str = to_string( span ); +# endif +} + +CASE( "narrow<>(): Allows narrowing double to float without MSVC level 4 warning C4127: conditional expression is constant [issue #115]" ) +{ +# if gsl_HAVE( EXCEPTIONS ) + try { (void) narrow<float>( 1.0 ); } catch(...) {} +# endif // gsl_HAVE( EXCEPTIONS ) +} + +CASE( "detail::is_compatible_container<>: Not a proper type trait [PR #238]" ) +{ +#if gsl_HAVE( TYPE_TRAITS ) && ! gsl_BETWEEN( gsl_COMPILER_MSVC_VERSION, 1, 140 ) + static_assert( std::is_base_of<gsl_lite::std11::false_type, gsl_lite::detail::is_compatible_container< int, int > >::value, "static assertion failed" ); +#endif +} + +// end of file diff --git a/thirdparty/gsl-lite/test/lest_cpp03.hpp b/thirdparty/gsl-lite/test/lest_cpp03.hpp new file mode 100644 index 000000000..63167c52c --- /dev/null +++ b/thirdparty/gsl-lite/test/lest_cpp03.hpp @@ -0,0 +1,1646 @@ +// Copyright 2013-2018 by Martin Moene +// +// lest is based on ideas by Kevlin Henney, see video at +// http://skillsmatter.com/podcast/agile-testing/kevlin-henney-rethinking-unit-testing-in-c-plus-plus +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef LEST_LEST_HPP_INCLUDED +#define LEST_LEST_HPP_INCLUDED + +#include <algorithm> +#include <iomanip> +#include <iostream> +#include <iterator> +#include <limits> +#include <sstream> +#include <stdexcept> +#include <set> +#include <string> +#include <utility> +#include <vector> + +#include <cctype> +#include <cmath> +#include <cstddef> +#include <cstdlib> +#include <ctime> + +#define lest_MAJOR 1 +#define lest_MINOR 35 +#define lest_PATCH 1 + +#define lest_VERSION lest_STRINGIFY(lest_MAJOR) "." lest_STRINGIFY(lest_MINOR) "." lest_STRINGIFY(lest_PATCH) + +#ifndef lest_FEATURE_COLOURISE +# define lest_FEATURE_COLOURISE 0 +#endif + +#ifndef lest_FEATURE_LITERAL_SUFFIX +# define lest_FEATURE_LITERAL_SUFFIX 0 +#endif + +#ifndef lest_FEATURE_REGEX_SEARCH +# define lest_FEATURE_REGEX_SEARCH 0 +#endif + +#ifndef lest_FEATURE_TIME +# define lest_FEATURE_TIME 1 +#endif + +#ifndef lest_FEATURE_TIME_PRECISION +#define lest_FEATURE_TIME_PRECISION 0 +#endif + +#ifdef _WIN32 +# define lest_PLATFORM_IS_WINDOWS 1 +#else +# define lest_PLATFORM_IS_WINDOWS 0 +#endif + +#if lest_FEATURE_REGEX_SEARCH +# include <regex> +#endif + +#if lest_FEATURE_TIME +# if lest_PLATFORM_IS_WINDOWS +# include <iomanip> +# include <Windows.h> +# else +# include <iomanip> +# include <sys/time.h> +# endif +#endif + +// Compiler warning suppression: + +#if defined (__clang__) +# pragma clang diagnostic ignored "-Waggregate-return" +# pragma clang diagnostic ignored "-Woverloaded-shift-op-parentheses" +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wdate-time" +#elif defined (__GNUC__) +# pragma GCC diagnostic ignored "-Waggregate-return" +# pragma GCC diagnostic push +#endif + +// Suppress shadow and unused-value warning for sections: + +#if defined (__clang__) +# define lest_SUPPRESS_WSHADOW _Pragma( "clang diagnostic push" ) \ + _Pragma( "clang diagnostic ignored \"-Wshadow\"" ) +# define lest_SUPPRESS_WUNUSED _Pragma( "clang diagnostic push" ) \ + _Pragma( "clang diagnostic ignored \"-Wunused-value\"" ) +# define lest_SUPPRESS_WUNREACHABLE _Pragma( "clang diagnostic push" ) +# define lest_SUPPRESS_WNORETVAL _Pragma( "clang diagnostic push" ) +# define lest_RESTORE_WARNINGS _Pragma( "clang diagnostic pop" ) + +#elif defined (__GNUC__) +# define lest_SUPPRESS_WSHADOW _Pragma( "GCC diagnostic push" ) \ + _Pragma( "GCC diagnostic ignored \"-Wshadow\"" ) +# define lest_SUPPRESS_WUNUSED _Pragma( "GCC diagnostic push" ) \ + _Pragma( "GCC diagnostic ignored \"-Wunused-value\"" ) +# define lest_SUPPRESS_WUNREACHABLE _Pragma( "GCC diagnostic push" ) +# define lest_SUPPRESS_WNORETVAL _Pragma( "GCC diagnostic push" ) +# define lest_RESTORE_WARNINGS _Pragma( "GCC diagnostic pop" ) +#elif defined( _MSC_VER) +# define lest_SUPPRESS_WSHADOW __pragma(warning(push)) __pragma(warning(disable: 4456)) +# define lest_SUPPRESS_WUNUSED __pragma(warning(push)) __pragma(warning(disable: 4100)) +# define lest_SUPPRESS_WUNREACHABLE __pragma(warning(push)) __pragma(warning(disable: 4702)) +# define lest_SUPPRESS_WNORETVAL __pragma(warning(push)) __pragma(warning(disable: 4715)) +# define lest_RESTORE_WARNINGS __pragma(warning(pop )) +#else +# define lest_SUPPRESS_WSHADOW /*empty*/ +# define lest_SUPPRESS_WUNUSED /*empty*/ +# define lest_SUPPRESS_WUNREACHABLE /*empty*/ +# define lest_SUPPRESS_WNORETVAL /*empty*/ +# define lest_RESTORE_WARNINGS /*empty*/ +#endif + +#if defined(__NVCOMPILER) +# define lest_SUPPRESS_CONTROLLING_EXPRESSION_IS_CONSTANT _Pragma("diag_suppress 236") +# define lest_RESTORE_CONTROLLING_EXPRESSION_IS_CONSTANT _Pragma("diag_default 236") +#else +# define lest_SUPPRESS_CONTROLLING_EXPRESSION_IS_CONSTANT +# define lest_RESTORE_CONTROLLING_EXPRESSION_IS_CONSTANT +#endif + +// Stringify: + +#define lest_STRINGIFY( x ) lest_STRINGIFY_( x ) +#define lest_STRINGIFY_( x ) #x + +// Compiler versions: + +#if defined( _MSC_VER ) && !defined( __clang__ ) +# define lest_COMPILER_MSVC_VERSION ( _MSC_VER / 10 - 10 * ( 5 + ( _MSC_VER < 1900 ) ) ) +#else +# define lest_COMPILER_MSVC_VERSION 0 +#endif + +#define lest_COMPILER_VERSION( major, minor, patch ) ( 10 * ( 10 * major + minor ) + patch ) + +#if defined (__clang__) +# define lest_COMPILER_CLANG_VERSION lest_COMPILER_VERSION( __clang_major__, __clang_minor__, __clang_patchlevel__ ) +#else +# define lest_COMPILER_CLANG_VERSION 0 +#endif + +#if defined (__GNUC__) +# define lest_COMPILER_GNUC_VERSION lest_COMPILER_VERSION( __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__ ) +#else +# define lest_COMPILER_GNUC_VERSION 0 +#endif + +// C++ language version detection (C++20 is speculative): +// Note: VC14.0/1900 (VS2015) lacks too much from C++14. + +#ifndef lest_CPLUSPLUS +# if defined(_MSVC_LANG ) && !defined(__clang__) +# define lest_CPLUSPLUS (_MSC_VER == 1900 ? 201103L : _MSVC_LANG ) +# else +# define lest_CPLUSPLUS __cplusplus +# endif +#endif + +#define lest_CPP98_OR_GREATER ( lest_CPLUSPLUS >= 199711L ) +#define lest_CPP11_OR_GREATER ( lest_CPLUSPLUS >= 201103L || lest_COMPILER_MSVC_VERSION >= 120 ) +#define lest_CPP14_OR_GREATER ( lest_CPLUSPLUS >= 201402L ) +#define lest_CPP17_OR_GREATER ( lest_CPLUSPLUS >= 201703L ) +#define lest_CPP20_OR_GREATER ( lest_CPLUSPLUS >= 202000L ) + +#define lest_CPP11_100 (lest_CPP11_OR_GREATER || lest_COMPILER_MSVC_VERSION >= 100) + +#ifndef __has_cpp_attribute +# define __has_cpp_attribute(name) 0 +#endif + +// Indicate argument as possibly unused, if possible: + +#if __has_cpp_attribute(maybe_unused) && lest_CPP17_OR_GREATER +# define lest_MAYBE_UNUSED(ARG) [[maybe_unused]] ARG +#elif defined (__GNUC__) +# define lest_MAYBE_UNUSED(ARG) ARG __attribute((unused)) +#else +# define lest_MAYBE_UNUSED(ARG) ARG +#endif + +// Presence of language and library features: + +#define lest_HAVE(FEATURE) ( lest_HAVE_##FEATURE ) + +#if lest_COMPILER_CLANG_VERSION +# ifdef __OBJC__ + // There are a bunch of inconsistencies about __EXCEPTIONS and __has_feature(cxx_exceptions) in Clang 3.4/3.5/3.6. + // We're interested in C++ exceptions, which can be checked by __has_feature(cxx_exceptions) in 3.5+. + // In pre-3.5, __has_feature(cxx_exceptions) can be true if ObjC exceptions are enabled, but C++ exceptions are disabled. + // The recommended way to check is `__EXCEPTIONS && __has_feature(cxx_exceptions)`. + // See https://releases.llvm.org/3.6.0/tools/clang/docs/ReleaseNotes.html#the-exceptions-macro + // Note: this is only relevant in Objective-C++, thus the ifdef. +# if __EXCEPTIONS && __has_feature(cxx_exceptions) +# define lest_HAVE_EXCEPTIONS 1 +# else +# define lest_HAVE_EXCEPTIONS 0 +# endif // __EXCEPTIONS && __has_feature(cxx_exceptions) +# else + // clang-cl doesn't define __EXCEPTIONS for MSVC compatibility (see https://reviews.llvm.org/D4065). + // Neither does Clang in MS-compatiblity mode. + // Let's hope no one tries to build Objective-C++ code using MS-compatibility mode or clang-cl. +# if __has_feature(cxx_exceptions) +# define lest_HAVE_EXCEPTIONS 1 +# else +# define lest_HAVE_EXCEPTIONS 0 +# endif +# endif +#elif lest_COMPILER_GNUC_VERSION +# if lest_COMPILER_GNUC_VERSION >= 1 && lest_COMPILER_GNUC_VERSION < 500 +# ifdef __EXCEPTIONS +# define lest_HAVE_EXCEPTIONS 1 +# else +# define lest_HAVE_EXCEPTIONS 0 +# endif // __EXCEPTIONS +# else +# ifdef __cpp_exceptions +# define lest_HAVE_EXCEPTIONS 1 +# else +# define lest_HAVE_EXCEPTIONS 0 +# endif // __cpp_exceptions +# endif // lest_COMPILER_GNUC_VERSION >= 1 && lest_COMPILER_GNUC_VERSION < 500 +#elif lest_COMPILER_MSVC_VERSION +# ifdef _CPPUNWIND +# define lest_HAVE_EXCEPTIONS 1 +# else +# define lest_HAVE_EXCEPTIONS 0 +# endif // _CPPUNWIND +#else +// For all other compilers, assume exceptions are always enabled. +# define lest_HAVE_EXCEPTIONS 1 +#endif + +// Exception handling helpers: + +#if lest_HAVE( EXCEPTIONS ) +# define lest_TRY try +# define lest_CATCH(x) catch (x) +# define lest_CATCH_ALL catch (...) +# define lest_THROW(x) throw x +# define lest_RETHROW throw +#else // ! lest_HAVE( EXCEPTIONS ) +# define lest_TRY if (1) +# define lest_CATCH(x) else if (0) +# define lest_CATCH_ALL else if (0) +# define lest_THROW(x) std::terminate() +# define lest_RETHROW +#endif // lest_HAVE( EXCEPTIONS ) + + +// Presence of C++11 language features: + +#define lest_HAVE_NOEXCEPT ( lest_CPP11_100 ) +#define lest_HAVE_NULLPTR ( lest_CPP11_100 ) + +// C++ feature usage: + +#if lest_HAVE( NULLPTR ) +# define lest_nullptr nullptr +#else +# define lest_nullptr NULL +#endif + +// Additional includes and tie: + +#if lest_CPP11_100 + +# include <cstdint> +# include <random> +# include <tuple> + +namespace lest +{ + using std::tie; +} + +#else + +# if !defined(__clang__) && defined(__GNUC__) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Weffc++" +# endif + +namespace lest +{ + // tie: + + template< typename T1, typename T2 > + struct Tie + { + Tie( T1 & first_, T2 & second_) + : first( first_), second( second_) {} + + std::pair<T1, T2> const & + operator=( std::pair<T1, T2> const & rhs ) + { + first = rhs.first; + second = rhs.second; + return rhs; + } + + private: + void operator=( Tie const & ); + + T1 & first; + T2 & second; + }; + + template< typename T1, typename T2 > + inline Tie<T1,T2> tie( T1 & first, T2 & second ) + { + return Tie<T1, T2>( first, second ); + } +} + +# if !defined(__clang__) && defined(__GNUC__) +# pragma GCC diagnostic pop +# endif + +#endif // lest_CPP11_100 + +namespace lest +{ + using std::abs; + using std::min; + using std::strtol; + using std::rand; + using std::srand; +} + +#if ! defined( lest_NO_SHORT_MACRO_NAMES ) && ! defined( lest_NO_SHORT_ASSERTION_NAMES ) +# define SETUP lest_SETUP +# define SECTION lest_SECTION + +# define EXPECT lest_EXPECT +# define EXPECT_NOT lest_EXPECT_NOT +# define EXPECT_NO_THROW lest_EXPECT_NO_THROW +# define EXPECT_THROWS lest_EXPECT_THROWS +# define EXPECT_THROWS_AS lest_EXPECT_THROWS_AS + +# define SCENARIO lest_SCENARIO +# define GIVEN lest_GIVEN +# define WHEN lest_WHEN +# define THEN lest_THEN +# define AND_WHEN lest_AND_WHEN +# define AND_THEN lest_AND_THEN +#endif + +#define lest_SCENARIO( specification, sketch ) \ + lest_CASE( specification, lest::text("Scenario: ") + sketch ) +#define lest_GIVEN( context ) lest_SETUP( lest::text(" Given: ") + context ) +#define lest_WHEN( story ) lest_SECTION( lest::text(" When: ") + story ) +#define lest_THEN( story ) lest_SECTION( lest::text(" Then: ") + story ) +#define lest_AND_WHEN( story ) lest_SECTION( lest::text("And then: ") + story ) +#define lest_AND_THEN( story ) lest_SECTION( lest::text("And then: ") + story ) + +#define lest_CASE( specification, proposition ) \ + static void lest_FUNCTION( lest::env & ); \ + static lest::add_test lest_REGISTRAR( specification, lest::test( proposition, lest_FUNCTION ) ); \ + static void lest_FUNCTION( lest_MAYBE_UNUSED( lest::env & lest_env ) ) + +#define lest_ADD_TEST( specification, test ) \ + specification.push_back( test ) + +#define lest_SETUP( context ) \ + for ( int lest__section = 0, lest__count = 1; lest__section < lest__count; lest__count -= 0==lest__section++ ) \ + for ( lest::ctx lest__ctx_setup( lest_env, context ); lest__ctx_setup; ) + +#define lest_SECTION( proposition ) \ + lest_SUPPRESS_WSHADOW \ + static int lest_UNIQUE( id ) = 0; \ + if ( lest::guard( lest_UNIQUE( id ), lest__section, lest__count ) ) \ + for ( int lest__section = 0, lest__count = 1; lest__section < lest__count; lest__count -= 0==lest__section++ ) \ + for ( lest::ctx lest__ctx_section( lest_env, proposition ); lest__ctx_section; ) \ + lest_RESTORE_WARNINGS + +#define lest_EXPECT( expr ) \ + do { \ + lest_TRY \ + { \ + lest_SUPPRESS_CONTROLLING_EXPRESSION_IS_CONSTANT \ + if ( lest::result score = lest_DECOMPOSE( expr ) ) \ + lest_THROW( lest::failure( lest_LOCATION, #expr, score.decomposition ) ); \ + else if ( lest_env.pass() ) \ + lest::report( lest_env.os, lest::passing( lest_LOCATION, #expr, score.decomposition, lest_env.zen() ), lest_env.context() ); \ + lest_RESTORE_CONTROLLING_EXPRESSION_IS_CONSTANT \ + } \ + lest_CATCH_ALL \ + { \ + lest::inform( lest_LOCATION, #expr ); \ + } \ + } while ( false ) + +#define lest_EXPECT_NOT( expr ) \ + do { \ + lest_TRY \ + { \ + lest_SUPPRESS_CONTROLLING_EXPRESSION_IS_CONSTANT \ + if ( lest::result score = lest_DECOMPOSE( expr ) ) \ + { \ + if ( lest_env.pass() ) \ + lest::report( lest_env.os, lest::passing( lest_LOCATION, lest::not_expr( #expr ), lest::not_expr( score.decomposition ), lest_env.zen() ), lest_env.context() ); \ + } \ + else \ + lest_THROW( lest::failure( lest_LOCATION, lest::not_expr( #expr ), lest::not_expr( score.decomposition ) ) ); \ + lest_RESTORE_CONTROLLING_EXPRESSION_IS_CONSTANT \ + } \ + lest_CATCH_ALL \ + { \ + lest::inform( lest_LOCATION, lest::not_expr( #expr ) ); \ + } \ + } while ( false ) + +#define lest_EXPECT_NO_THROW( expr ) \ + do \ + { \ + lest_TRY \ + { \ + lest_SUPPRESS_WUNUSED \ + expr; \ + lest_RESTORE_WARNINGS \ + } \ + lest_CATCH_ALL { lest::inform( lest_LOCATION, #expr ); } \ + if ( lest_env.pass() ) \ + lest::report( lest_env.os, lest::got_none( lest_LOCATION, #expr ), lest_env.context() ); \ + } while ( false ) + +#define lest_EXPECT_THROWS( expr ) \ + do \ + { \ + lest_TRY \ + { \ + lest_SUPPRESS_WUNUSED \ + expr; \ + lest_RESTORE_WARNINGS \ + } \ + lest_CATCH_ALL \ + { \ + if ( lest_env.pass() ) \ + lest::report( lest_env.os, lest::got( lest_LOCATION, #expr ), lest_env.context() ); \ + break; \ + } \ + lest_THROW( lest::expected( lest_LOCATION, #expr ) ); \ + } \ + while ( false ) + +#define lest_EXPECT_THROWS_AS( expr, excpt ) \ + do \ + { \ + lest_TRY \ + { \ + lest_SUPPRESS_WUNUSED \ + expr; \ + lest_RESTORE_WARNINGS \ + } \ + lest_CATCH( excpt & ) \ + { \ + if ( lest_env.pass() ) \ + lest::report( lest_env.os, lest::got( lest_LOCATION, #expr, lest::of_type( #excpt ) ), lest_env.context() ); \ + break; \ + } \ + lest_CATCH_ALL {} \ + lest_THROW( lest::expected( lest_LOCATION, #expr, lest::of_type( #excpt ) ) ); \ + } \ + while ( false ) + +#define lest_DECOMPOSE( expr ) ( lest::expression_decomposer() << expr ) + +#define lest_STRING( name ) lest_STRING2( name ) +#define lest_STRING2( name ) #name + +#define lest_UNIQUE( name ) lest_UNIQUE2( name, __LINE__ ) +#define lest_UNIQUE2( name, line ) lest_UNIQUE3( name, line ) +#define lest_UNIQUE3( name, line ) name ## line + +#define lest_LOCATION lest::location(__FILE__, __LINE__) + +#define lest_FUNCTION lest_UNIQUE(__lest_function__ ) +#define lest_REGISTRAR lest_UNIQUE(__lest_registrar__ ) + +#define lest_DIMENSION_OF( a ) ( sizeof(a) / sizeof(0[a]) ) + +namespace lest { + +const int exit_max_value = 255; + +typedef std::string text; +typedef std::vector<text> texts; + +struct env; + +struct test +{ + text name; + void (* behaviour)( env & ); + + test( text name_, void (* behaviour_)( env & ) ) + : name( name_), behaviour( behaviour_) {} +}; + +typedef std::vector<test> tests; +typedef tests test_specification; + +struct add_test +{ + add_test( tests & specification, test const & test_case ) + { + specification.push_back( test_case ); + } +}; + +struct result +{ + const bool passed; + const text decomposition; + + template< typename T > + result( T const & passed_, text decomposition_) + : passed( !!passed_), decomposition( decomposition_) {} + + operator bool() { return ! passed; } +}; + +struct location +{ + const text file; + const int line; + + location( text file_, int line_) + : file( file_), line( line_) {} +}; + +struct comment +{ + const text info; + + comment( text info_) : info( info_) {} + operator bool() { return ! info.empty(); } +}; + +struct message : std::runtime_error +{ + const text kind; + const location where; + const comment note; + +#if ! lest_CPP11_OR_GREATER + ~message() throw() {} +#endif + + message( text kind_, location where_, text expr_, text note_ = "" ) + : std::runtime_error( expr_), kind( kind_), where( where_), note( note_) {} +}; + +struct failure : message +{ + failure( location where_, text expr_, text decomposition_) + : message( "failed", where_, expr_ + " for " + decomposition_) {} +}; + +struct success : message +{ + success( text kind_, location where_, text expr_, text note_ = "" ) + : message( kind_, where_, expr_, note_) {} +}; + +struct passing : success +{ + passing( location where_, text expr_, text decomposition_, bool zen ) + : success( "passed", where_, expr_ + (zen ? "":" for " + decomposition_) ) {} +}; + +struct got_none : success +{ + got_none( location where_, text expr_) + : success( "passed: got no exception", where_, expr_) {} +}; + +struct got : success +{ + got( location where_, text expr_) + : success( "passed: got exception", where_, expr_) {} + + got( location where_, text expr_, text excpt_) + : success( "passed: got exception " + excpt_, where_, expr_) {} +}; + +struct expected : message +{ + expected( location where_, text expr_, text excpt_ = "" ) + : message( "failed: didn't get exception", where_, expr_, excpt_) {} +}; + +struct unexpected : message +{ + unexpected( location where_, text expr_, text note_ = "" ) + : message( "failed: got unexpected exception", where_, expr_, note_) {} +}; + +struct guard +{ + int & id; + int const & section; + + guard( int & id_, int const & section_, int & count ) + : id( id_ ), section( section_ ) + { + if ( section == 0 ) + id = count++ - 1; + } + operator bool() { return id == section; } +}; + +class approx +{ +public: + explicit approx ( double magnitude ) + : epsilon_ ( 100.0 * static_cast<double>( std::numeric_limits<float>::epsilon() ) ) + , scale_ ( 1.0 ) + , magnitude_( magnitude ) {} + + static approx custom() { return approx( 0 ); } + + approx operator()( double new_magnitude ) + { + approx appr( new_magnitude ); + appr.epsilon( epsilon_ ); + appr.scale ( scale_ ); + return appr; + } + + double magnitude() const { return magnitude_; } + + approx & epsilon( double epsilon ) { epsilon_ = epsilon; return *this; } + approx & scale ( double scale ) { scale_ = scale; return *this; } + + friend bool operator == ( double lhs, approx const & rhs ) + { + // Thanks to Richard Harris for his help refining this formula. + return lest::abs( lhs - rhs.magnitude_ ) < rhs.epsilon_ * ( rhs.scale_ + (lest::min)( lest::abs( lhs ), lest::abs( rhs.magnitude_ ) ) ); + } + + friend bool operator == ( approx const & lhs, double rhs ) { return operator==( rhs, lhs ); } + friend bool operator != ( double lhs, approx const & rhs ) { return !operator==( lhs, rhs ); } + friend bool operator != ( approx const & lhs, double rhs ) { return !operator==( rhs, lhs ); } + + friend bool operator <= ( double lhs, approx const & rhs ) { return lhs < rhs.magnitude_ || lhs == rhs; } + friend bool operator <= ( approx const & lhs, double rhs ) { return lhs.magnitude_ < rhs || lhs == rhs; } + friend bool operator >= ( double lhs, approx const & rhs ) { return lhs > rhs.magnitude_ || lhs == rhs; } + friend bool operator >= ( approx const & lhs, double rhs ) { return lhs.magnitude_ > rhs || lhs == rhs; } + +private: + double epsilon_; + double scale_; + double magnitude_; +}; + +inline bool is_false( ) { return false; } +inline bool is_true ( bool flag ) { return flag; } + +inline text not_expr( text message ) +{ + return "! ( " + message + " )"; +} + +inline text with_message( text message ) +{ + return "with message \"" + message + "\""; +} + +inline text of_type( text type ) +{ + return "of type " + type; +} + +inline void inform( location where, text expr ) +{ + lest_TRY + { + lest_RETHROW; + } + lest_CATCH( failure const & ) + { + lest_RETHROW; + } + lest_CATCH( std::exception const & e ) + { +#if lest_HAVE( EXCEPTIONS ) + lest_THROW( unexpected( where, expr, with_message( e.what() ) ) ); +#endif // lest_HAVE( EXCEPTIONS ) + } + lest_CATCH_ALL + { + lest_THROW( unexpected( where, expr, "of unknown type" ) ); + } +} + +// Expression decomposition: + +inline bool unprintable( char c ) +{ + // The cast helps suppress warnings ("-Wtype-limits" on GCC) on architectures where `char` is unsigned. + return 0 <= static_cast<signed char>(c) && c < ' '; +} + +inline std::string to_hex_string(char c) +{ + std::ostringstream os; + os << "\\x" << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>( static_cast<unsigned char>(c) ); + return os.str(); +} + +inline std::string transformed( char chr ) +{ + struct Tr { char chr; char const * str; } table[] = + { + {'\\', "\\\\" }, + {'\r', "\\r" }, {'\f', "\\f" }, + {'\n', "\\n" }, {'\t', "\\t" }, + }; + + for ( Tr * pos = table; pos != table + lest_DIMENSION_OF( table ); ++pos ) + { + if ( chr == pos->chr ) + return pos->str; + } + + return unprintable( chr ) ? to_hex_string( chr ) : std::string( 1, chr ); +} + +template< typename C > +inline std::string make_tran_string( std::basic_string< C > const & txt ) +{ + std::ostringstream os; + for( typename std::basic_string< C >::const_iterator pos = txt.begin(); pos != txt.end(); ++pos ) + os << transformed( static_cast<char>( *pos ) ); + return os.str(); +} + +template< typename T > +inline std::string to_string( T const & value ); + +#if lest_CPP11_OR_GREATER || lest_COMPILER_MSVC_VERSION >= 100 +inline std::string to_string( std::nullptr_t const & ) { return "nullptr"; } +#endif +inline std::string to_string( std::string const & txt ) { return "\"" + make_tran_string( txt ) + "\""; } +inline std::string to_string( wchar_t const * const & txt ) { return "\"" + make_tran_string( std::wstring( txt ) ) + "\""; } +inline std::string to_string( char const * const & txt ) { return "\"" + make_tran_string( std::string( txt ) ) + "\""; } +inline std::string to_string( char const & chr ) { return "'" + make_tran_string( std::string( 1, chr ) ) + "'"; } + +inline std::string to_string( signed char const & chr ) { return to_string( static_cast<char>( chr ) ); } +inline std::string to_string( unsigned char const & chr ) { return to_string( static_cast<char>( chr ) ); } + +inline std::ostream & operator<<( std::ostream & os, approx const & appr ) +{ + return os << appr.magnitude(); +} + +template< typename T > +inline std::string make_string( T const * ptr ) +{ + // Note showbase affects the behavior of /integer/ output; + std::ostringstream os; + os << std::internal << std::hex << std::showbase << std::setw( 2 + 2 * sizeof(T*) ) << std::setfill('0') << reinterpret_cast<std::ptrdiff_t>( ptr ); + return os.str(); +} + +template< typename C, typename R > +inline std::string make_string( R C::* ptr ) +{ + std::ostringstream os; + os << std::internal << std::hex << std::showbase << std::setw( 2 + 2 * sizeof(R C::* ) ) << std::setfill('0') << ptr; + return os.str(); +} + +template< typename T > +struct string_maker +{ + static std::string to_string( T const & value ) + { + std::ostringstream os; os << std::boolalpha << value; + return os.str(); + } +}; + +template< > +struct string_maker< wchar_t > +{ + static std::string to_string( wchar_t value ) + { + std::ostringstream os; os << std::boolalpha << static_cast<char>( value ); + return os.str(); + } +}; + +template< typename T > +struct string_maker< T* > +{ + static std::string to_string( T const * ptr ) + { + return ! ptr ? lest_STRING( lest_nullptr ) : make_string( ptr ); + } +}; + +template< typename C, typename R > +struct string_maker< R C::* > +{ + static std::string to_string( R C::* ptr ) + { + return ! ptr ? lest_STRING( lest_nullptr ) : make_string( ptr ); + } +}; + +template< typename T > +inline std::string to_string( T const & value ) +{ + return string_maker<T>::to_string( value ); +} + +template< typename T1, typename T2 > +std::string to_string( std::pair<T1,T2> const & pair ) +{ + std::ostringstream oss; + oss << "{ " << to_string( pair.first ) << ", " << to_string( pair.second ) << " }"; + return oss.str(); +} + +#if lest_CPP11_OR_GREATER + +template< typename TU, std::size_t N > +struct make_tuple_string +{ + static std::string make( TU const & tuple ) + { + std::ostringstream os; + os << to_string( std::get<N - 1>( tuple ) ) << ( N < std::tuple_size<TU>::value ? ", ": " "); + return make_tuple_string<TU, N - 1>::make( tuple ) + os.str(); + } +}; + +template< typename TU > +struct make_tuple_string<TU, 0> +{ + static std::string make( TU const & ) { return ""; } +}; + +template< typename ...TS > +auto to_string( std::tuple<TS...> const & tuple ) -> std::string +{ + return "{ " + make_tuple_string<std::tuple<TS...>, sizeof...(TS)>::make( tuple ) + "}"; +} + +#endif // lest_CPP11_OR_GREATER + +template< typename L, typename R > +std::string to_string( L const & lhs, std::string op, R const & rhs ) +{ + std::ostringstream os; os << to_string( lhs ) << " " << op << " " << to_string( rhs ); return os.str(); +} + +template< typename L > +struct expression_lhs +{ + L lhs; + + expression_lhs( L lhs_) : lhs( lhs_) {} + + operator result() { return result( !!lhs, to_string( lhs ) ); } + + template< typename R > result operator==( R const & rhs ) { return result( lhs == rhs, to_string( lhs, "==", rhs ) ); } + template< typename R > result operator!=( R const & rhs ) { return result( lhs != rhs, to_string( lhs, "!=", rhs ) ); } + template< typename R > result operator< ( R const & rhs ) { return result( lhs < rhs, to_string( lhs, "<" , rhs ) ); } + template< typename R > result operator<=( R const & rhs ) { return result( lhs <= rhs, to_string( lhs, "<=", rhs ) ); } + template< typename R > result operator> ( R const & rhs ) { return result( lhs > rhs, to_string( lhs, ">" , rhs ) ); } + template< typename R > result operator>=( R const & rhs ) { return result( lhs >= rhs, to_string( lhs, ">=", rhs ) ); } +}; + +struct expression_decomposer +{ + template< typename L > + expression_lhs<L const &> operator<< ( L const & operand ) + { + return expression_lhs<L const &>( operand ); + } +}; + +// Reporter: + +#if lest_FEATURE_COLOURISE + +inline text red ( text words ) { return "\033[1;31m" + words + "\033[0m"; } +inline text green( text words ) { return "\033[1;32m" + words + "\033[0m"; } +inline text gray ( text words ) { return "\033[1;30m" + words + "\033[0m"; } + +inline bool starts_with( text words, text with ) +{ + return 0 == words.find( with ); +} + +inline text replace( text words, text from, text to ) +{ + size_t pos = words.find( from ); + return pos == std::string::npos ? words : words.replace( pos, from.length(), to ); +} + +inline text colour( text words ) +{ + if ( starts_with( words, "failed" ) ) return replace( words, "failed", red ( "failed" ) ); + else if ( starts_with( words, "passed" ) ) return replace( words, "passed", green( "passed" ) ); + + return replace( words, "for", gray( "for" ) ); +} + +inline bool is_cout( std::ostream & os ) { return &os == &std::cout; } + +struct colourise +{ + const text words; + + colourise( text words ) + : words( words ) {} + + // only colourise for std::cout, not for a stringstream as used in tests: + + std::ostream & operator()( std::ostream & os ) const + { + return is_cout( os ) ? os << colour( words ) : os << words; + } +}; + +inline std::ostream & operator<<( std::ostream & os, colourise words ) { return words( os ); } +#else +inline text colourise( text words ) { return words; } +#endif + +inline text pluralise( text word,int n ) +{ + return n == 1 ? word : word + "s"; +} + +inline std::ostream & operator<<( std::ostream & os, comment note ) +{ + return os << (note ? " " + note.info : "" ); +} + +inline std::ostream & operator<<( std::ostream & os, location where ) +{ +#ifdef __GNUG__ + return os << where.file << ":" << where.line; +#else + return os << where.file << "(" << where.line << ")"; +#endif +} + +inline void report( std::ostream & os, message const & e, text test ) +{ + os << e.where << ": " << colourise( e.kind ) << e.note << ": " << test << ": " << colourise( e.what() ) << std::endl; +} + +// Test runner: + +#if lest_FEATURE_REGEX_SEARCH + inline bool search( text re, text line ) + { + return std::regex_search( line, std::regex( re ) ); + } +#else + inline bool case_insensitive_equal( char a, char b ) + { + return tolower( a ) == tolower( b ); + } + + inline bool search( text part, text line ) + { + return std::search( + line.begin(), line.end(), + part.begin(), part.end(), case_insensitive_equal ) != line.end(); + } +#endif + +inline bool match( texts whats, text line ) +{ + for ( texts::iterator what = whats.begin(); what != whats.end() ; ++what ) + { + if ( search( *what, line ) ) + return true; + } + return false; +} + +inline bool hidden( text name ) +{ +#if lest_FEATURE_REGEX_SEARCH + texts skipped; skipped.push_back( "\\[\\.\\]" ); skipped.push_back( "\\[hide\\]" ); +#else + texts skipped; skipped.push_back( "[." ); skipped.push_back( "[hide]" ); +#endif + return match( skipped, name ); +} + +inline bool none( texts args ) +{ + return args.size() == 0; +} + +inline bool select( text name, texts include ) +{ + if ( none( include ) ) + { + return ! hidden( name ); + } + + bool any = false; + for ( texts::reverse_iterator pos = include.rbegin(); pos != include.rend(); ++pos ) + { + text & part = *pos; + + if ( part == "@" || part == "*" ) + return true; + + if ( search( part, name ) ) + return true; + + if ( '!' == part[0] ) + { + any = true; + if ( search( part.substr(1), name ) ) + return false; + } + else + { + any = false; + } + } + return any && ! hidden( name ); +} + +inline int indefinite( int repeat ) { return repeat == -1; } + +#if lest_CPP11_OR_GREATER +typedef std::mt19937::result_type seed_t; +#else +typedef unsigned int seed_t; +#endif + +struct options +{ + options() + : help(false), abort(false), count(false), list(false), tags(false), time(false) + , pass(false), zen(false), lexical(false), random(false), verbose(false), version(false), repeat(1), seed(0) {} + + bool help; + bool abort; + bool count; + bool list; + bool tags; + bool time; + bool pass; + bool zen; + bool lexical; + bool random; + bool verbose; + bool version; + int repeat; + seed_t seed; +}; + +struct env +{ + std::ostream & os; + options opt; + text testing; + std::vector< text > ctx; + + env( std::ostream & out, options option ) + : os( out ), opt( option ), testing(), ctx() {} + + env & operator()( text test ) + { + clear(); testing = test; return *this; + } + + bool abort() { return opt.abort; } + bool pass() { return opt.pass; } + bool zen() { return opt.zen; } + + void clear() { ctx.clear(); } + void pop() { ctx.pop_back(); } + void push( text proposition ) { ctx.push_back( proposition ); } + + text context() { return testing + sections(); } + + text sections() + { + if ( ! opt.verbose ) + return ""; + + text msg; + for( size_t i = 0; i != ctx.size(); ++i ) + { + msg += "\n " + ctx[i]; + } + return msg; + } +}; + +struct ctx +{ + env & environment; + bool once; + + ctx( env & environment_, text proposition_ ) + : environment( environment_), once( true ) + { + environment.push( proposition_); + } + + ~ctx() + { +#if lest_CPP17_OR_GREATER + if ( std::uncaught_exceptions() == 0 ) +#else + if ( ! std::uncaught_exception() ) +#endif + { + environment.pop(); + } + } + + operator bool() { bool result = once; once = false; return result; } +}; + +struct action +{ + std::ostream & os; + + action( std::ostream & out ) : os( out ) {} + + operator int() { return 0; } + bool abort() { return false; } + action & operator()( test ) { return *this; } + +private: + action( action const & ); + void operator=( action const & ); +}; + +struct print : action +{ + print( std::ostream & out ) : action( out ) {} + + print & operator()( test testing ) + { + os << testing.name << "\n"; return *this; + } +}; + +inline texts tags( text name, texts result = texts() ) +{ + size_t none = std::string::npos; + size_t lb = name.find_first_of( "[" ); + size_t rb = name.find_first_of( "]" ); + + if ( lb == none || rb == none ) + return result; + + result.push_back( name.substr( lb, rb - lb + 1 ) ); + + return tags( name.substr( rb + 1 ), result ); +} + +struct ptags : action +{ + std::set<text> result; + + ptags( std::ostream & out ) : action( out ), result() {} + + ptags & operator()( test testing ) + { + texts tags_( tags( testing.name ) ); + for ( texts::iterator pos = tags_.begin(); pos != tags_.end() ; ++pos ) + result.insert( *pos ); + + return *this; + } + + ~ptags() + { + std::copy( result.begin(), result.end(), std::ostream_iterator<text>( os, "\n" ) ); + } +}; + +struct count : action +{ + int n; + + count( std::ostream & out ) : action( out ), n( 0 ) {} + + count & operator()( test ) { ++n; return *this; } + + ~count() + { + os << n << " selected " << pluralise("test", n) << "\n"; + } +}; + +#if lest_FEATURE_TIME + +#if lest_PLATFORM_IS_WINDOWS +# if ! lest_CPP11_OR_GREATER && ! lest_COMPILER_MSVC_VERSION + typedef unsigned long uint64_t; +# elif lest_COMPILER_MSVC_VERSION >= 60 && lest_COMPILER_MSVC_VERSION < 100 + typedef /*un*/signed __int64 uint64_t; +# else + using ::uint64_t; +# endif +#else +# if ! lest_CPP11_OR_GREATER + typedef unsigned long long uint64_t; +# endif +#endif + +#if lest_PLATFORM_IS_WINDOWS + inline uint64_t current_ticks() + { + static LARGE_INTEGER hz = {{ 0,0 }}, hzo = {{ 0,0 }}; + if ( ! hz.QuadPart ) + { + QueryPerformanceFrequency( &hz ); + QueryPerformanceCounter ( &hzo ); + } + LARGE_INTEGER t = {{ 0,0 }}; QueryPerformanceCounter( &t ); + + return uint64_t( ( ( t.QuadPart - hzo.QuadPart ) * 1000000 ) / hz.QuadPart ); + } +#else + inline uint64_t current_ticks() + { + timeval t; gettimeofday( &t, lest_nullptr ); + return static_cast<uint64_t>( t.tv_sec ) * 1000000ull + static_cast<uint64_t>( t.tv_usec ); + } +#endif + +struct timer +{ + const uint64_t start_ticks; + + timer() : start_ticks( current_ticks() ) {} + + double elapsed_seconds() const + { + return static_cast<double>( current_ticks() - start_ticks ) / 1e6; + } +}; + +struct times : action +{ + env output; + int selected; + int failures; + + timer total; + + times( std::ostream & out, options option ) + : action( out ), output( out, option ), selected( 0 ), failures( 0 ), total() + { + os << std::setfill(' ') << std::fixed << std::setprecision( lest_FEATURE_TIME_PRECISION ); + } + + operator int() { return failures; } + + bool abort() { return output.abort() && failures > 0; } + + times & operator()( test testing ) + { + timer t; + + lest_TRY + { + testing.behaviour( output( testing.name ) ); + } + lest_CATCH( message const & ) + { + ++failures; + } + + os << std::setw(5) << ( 1000 * t.elapsed_seconds() ) << " ms: " << testing.name << "\n"; + + return *this; + } + + ~times() + { + os << "Elapsed time: " << std::setprecision(1) << total.elapsed_seconds() << " s\n"; + } +}; +#else +struct times : action { times( std::ostream & out, options ) : action( out ) {} }; +#endif + +struct confirm : action +{ + env output; + int selected; + int failures; + + confirm( std::ostream & out, options option ) + : action( out ), output( out, option ), selected( 0 ), failures( 0 ) {} + + operator int() { return failures; } + + bool abort() { return output.abort() && failures > 0; } + + confirm & operator()( test testing ) + { + lest_TRY + { + ++selected; testing.behaviour( output( testing.name ) ); + } + lest_CATCH( message const & e ) + { + ++failures; +#if lest_HAVE( EXCEPTIONS ) + report( os, e, output.context() ); +#endif // lest_HAVE( EXCEPTIONS ) + } + return *this; + } + + ~confirm() + { + if ( failures > 0 ) + { + os << failures << " out of " << selected << " selected " << pluralise("test", selected) << " " << colourise( "failed.\n" ); + } + else if ( output.pass() ) + { + os << "All " << selected << " selected " << pluralise("test", selected) << " " << colourise( "passed.\n" ); + } + } +}; + +template< typename Action > +bool abort( Action & perform ) +{ + return perform.abort(); +} + +template< typename Action > +Action & for_test( tests specification, texts in, Action & perform, int n = 1 ) +{ + for ( int i = 0; indefinite( n ) || i < n; ++i ) + { + for ( tests::iterator pos = specification.begin(); pos != specification.end() ; ++pos ) + { + test & testing = *pos; + + if ( select( testing.name, in ) ) + if ( abort( perform( testing ) ) ) + return perform; + } + } + return perform; +} + +inline bool test_less( test const & a, test const & b ) { return a.name < b.name; } + +inline void sort( tests & specification ) +{ + std::sort( specification.begin(), specification.end(), test_less ); +} + +// Use struct to avoid VC6 error C2664 when using free function: + +struct rng { int operator()( int n ) { return lest::rand() % n; } }; + +inline void shuffle( tests & specification, options option ) +{ +#if lest_CPP11_OR_GREATER + std::shuffle( specification.begin(), specification.end(), std::mt19937( option.seed ) ); +#else + lest::srand( option.seed ); + + rng generator; + std::random_shuffle( specification.begin(), specification.end(), generator ); +#endif +} + +inline int stoi( text num ) +{ + return static_cast<int>( lest::strtol( num.c_str(), lest_nullptr, 10 ) ); +} + +inline bool is_number( text arg ) +{ + const text digits = "0123456789"; + return text::npos != arg.find_first_of ( digits ) + && text::npos == arg.find_first_not_of( digits ); +} + +lest_SUPPRESS_WNORETVAL +inline seed_t seed( text opt, text arg ) +{ + // std::time_t: implementation dependent + + if ( arg == "time" ) + return static_cast<seed_t>( time( lest_nullptr ) ); + + if ( is_number( arg ) ) + return static_cast<seed_t>( lest::stoi( arg ) ); + + lest_THROW( std::runtime_error( "expecting 'time' or positive number with option '" + opt + "', got '" + arg + "' (try option --help)" ) ); +} + +inline int repeat( text opt, text arg ) +{ + const int num = lest::stoi( arg ); + + if ( indefinite( num ) || num >= 0 ) + return num; + + lest_THROW( std::runtime_error( "expecting '-1' or positive number with option '" + opt + "', got '" + arg + "' (try option --help)" ) ); +} +lest_RESTORE_WARNINGS + +inline std::pair<text, text> +split_option( text arg ) +{ + text::size_type pos = arg.rfind( '=' ); + + return pos == text::npos + ? std::make_pair( arg, text() ) + : std::make_pair( arg.substr( 0, pos ), arg.substr( pos + 1 ) ); +} + +inline std::pair<options, texts> +split_arguments( texts args ) +{ + options option; texts in; + + bool in_options = true; + + for ( texts::iterator pos = args.begin(); pos != args.end() ; ++pos ) + { + text opt, val, arg = *pos; + tie( opt, val ) = split_option( arg ); + + if ( in_options ) + { + if ( opt[0] != '-' ) { in_options = false; } + else if ( opt == "--" ) { in_options = false; continue; } + else if ( opt == "-h" || "--help" == opt ) { option.help = true; continue; } + else if ( opt == "-a" || "--abort" == opt ) { option.abort = true; continue; } + else if ( opt == "-c" || "--count" == opt ) { option.count = true; continue; } + else if ( opt == "-g" || "--list-tags" == opt ) { option.tags = true; continue; } + else if ( opt == "-l" || "--list-tests" == opt ) { option.list = true; continue; } + else if ( opt == "-t" || "--time" == opt ) { option.time = true; continue; } + else if ( opt == "-p" || "--pass" == opt ) { option.pass = true; continue; } + else if ( opt == "-z" || "--pass-zen" == opt ) { option.zen = true; continue; } + else if ( opt == "-v" || "--verbose" == opt ) { option.verbose = true; continue; } + else if ( "--version" == opt ) { option.version = true; continue; } + else if ( opt == "--order" && "declared" == val ) { /* by definition */ ; continue; } + else if ( opt == "--order" && "lexical" == val ) { option.lexical = true; continue; } + else if ( opt == "--order" && "random" == val ) { option.random = true; continue; } + else if ( opt == "--random-seed" ) { option.seed = seed ( "--random-seed", val ); continue; } + else if ( opt == "--repeat" ) { option.repeat = repeat( "--repeat" , val ); continue; } + else lest_THROW( std::runtime_error( "unrecognised option '" + opt + "' (try option --help)" ) ); + } + in.push_back( arg ); + } + option.pass = option.pass || option.zen; + + return std::make_pair( option, in ); +} + +inline int usage( std::ostream & os ) +{ + os << + "\nUsage: test [options] [test-spec ...]\n" + "\n" + "Options:\n" + " -h, --help this help message\n" + " -a, --abort abort at first failure\n" + " -c, --count count selected tests\n" + " -g, --list-tags list tags of selected tests\n" + " -l, --list-tests list selected tests\n" + " -p, --pass also report passing tests\n" + " -z, --pass-zen ... without expansion\n" +#if lest_FEATURE_TIME + " -t, --time list duration of selected tests\n" +#endif + " -v, --verbose also report passing or failing sections\n" + " --order=declared use source code test order (default)\n" + " --order=lexical use lexical sort test order\n" + " --order=random use random test order\n" + " --random-seed=n use n for random generator seed\n" + " --random-seed=time use time for random generator seed\n" + " --repeat=n repeat selected tests n times (-1: indefinite)\n" + " --version report lest version and compiler used\n" + " -- end options\n" + "\n" + "Test specification:\n" + " \"@\", \"*\" all tests, unless excluded\n" + " empty all tests, unless tagged [hide] or [.optional-name]\n" +#if lest_FEATURE_REGEX_SEARCH + " \"re\" select tests that match regular expression\n" + " \"!re\" omit tests that match regular expression\n" +#else + " \"text\" select tests that contain text (case insensitive)\n" + " \"!text\" omit tests that contain text (case insensitive)\n" +#endif + ; + return 0; +} + +inline text compiler() +{ + std::ostringstream os; +#if defined (__clang__ ) + os << "clang " << __clang_version__; +#elif defined (__GNUC__ ) + os << "gcc " << __GNUC__ << "." << __GNUC_MINOR__ << "." << __GNUC_PATCHLEVEL__; +#elif defined ( _MSC_VER ) + os << "MSVC " << lest_COMPILER_MSVC_VERSION << " (" << _MSC_VER << ")"; +#else + os << "[compiler]"; +#endif + return os.str(); +} + +inline int version( std::ostream & os ) +{ + os << "lest version " << lest_VERSION << "\n" +// Disabled because __DATE__ and __TIME__ are PCH-unfriendly +// << "Compiled with " << compiler() << " on " << __DATE__ << " at " << __TIME__ << ".\n" + << "For more information, see https://github.com/martinmoene/lest.\n"; + return 0; +} + +inline int run( tests specification, texts arguments, std::ostream & os = std::cout ) +{ + lest_TRY + { + options option; texts in; + tie( option, in ) = split_arguments( arguments ); + + if ( option.lexical ) { sort( specification ); } + if ( option.random ) { shuffle( specification, option ); } + + if ( option.help ) { return usage ( os ); } + if ( option.version ) { return version( os ); } + if ( option.count ) { count count_( os ); return for_test( specification, in, count_ ); } + if ( option.list ) { print print_( os ); return for_test( specification, in, print_ ); } + if ( option.tags ) { ptags ptags_( os ); return for_test( specification, in, ptags_ ); } + if ( option.time ) { times times_( os, option ); return for_test( specification, in, times_ ); } + + { confirm confirm_( os, option ); return for_test( specification, in, confirm_, option.repeat ); } + } + lest_CATCH( std::exception const & e ) + { +#if lest_HAVE( EXCEPTIONS ) + os << "Error: " << e.what() << "\n"; +#endif // lest_HAVE( EXCEPTIONS ) + return 1; + } +} + +// VC6: make<cont>(first,last) replaces cont(first,last) + +template< typename C, typename T > +C make( T const * first, T const * const last ) +{ + C result; + for ( ; first != last; ++first ) + { + result.push_back( *first ); + } + return result; +} + +inline tests make_tests( test const * first, test const * const last ) +{ + return make<tests>( first, last ); +} + +inline texts make_texts( char const * const * first, char const * const * last ) +{ + return make<texts>( first, last ); +} + +// Traversal of test[N] (test_specification[N]) set up to also work with MSVC6: + +template< typename C > test const * test_begin( C const & c ) { return &*c; } +template< typename C > test const * test_end( C const & c ) { return test_begin( c ) + lest_DIMENSION_OF( c ); } + +template< typename C > char const * const * text_begin( C const & c ) { return &*c; } +template< typename C > char const * const * text_end( C const & c ) { return text_begin( c ) + lest_DIMENSION_OF( c ); } + +template< typename C > tests make_tests( C const & c ) { return make_tests( test_begin( c ), test_end( c ) ); } +template< typename C > texts make_texts( C const & c ) { return make_texts( text_begin( c ), text_end( c ) ); } + +inline int run( tests const & specification, int argc, char ** argv, std::ostream & os = std::cout ) +{ + return run( specification, make_texts( argv + 1, argv + argc ), os ); +} + +inline int run( tests const & specification, std::ostream & os = std::cout ) +{ + std::cout.sync_with_stdio( false ); + return (min)( run( specification, texts(), os ), exit_max_value ); +} + +template< typename C > +int run( C const & specification, texts args, std::ostream & os = std::cout ) +{ + return run( make_tests( specification ), args, os ); +} + +template< typename C > +int run( C const & specification, int argc, char ** argv, std::ostream & os = std::cout ) +{ + return run( make_tests( specification ), argv, argc, os ); +} + +template< typename C > +int run( C const & specification, std::ostream & os = std::cout ) +{ + return run( make_tests( specification ), os ); +} + +} // namespace lest + +#if defined (__clang__) +# pragma clang diagnostic pop +#elif defined (__GNUC__) +# pragma GCC diagnostic pop +#endif + +#endif // LEST_LEST_HPP_INCLUDED diff --git a/thirdparty/gsl-lite/test/not_null.t.cpp b/thirdparty/gsl-lite/test/not_null.t.cpp new file mode 100644 index 000000000..32430c346 --- /dev/null +++ b/thirdparty/gsl-lite/test/not_null.t.cpp @@ -0,0 +1,1956 @@ +// +// gsl-lite is based on GSL: Guidelines Support Library. +// For more information see https://github.com/gsl-lite/gsl-lite +// +// Copyright (c) 2015-2019 Martin Moene +// Copyright (c) 2019-2021 Moritz Beutel +// Copyright (c) 2015-2018 Microsoft Corporation. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "gsl-lite.t.hpp" +#include <vector> +#include <functional> + +using namespace gsl_lite; + +namespace { + +struct MyBase {}; +struct MyDerived : public MyBase {}; +struct Unrelated {}; + +// Stand-in for a user-defined ref-counted class. +template<typename T> +struct RefCounted +{ + RefCounted( T * p ) : p_( p ) {} + operator T *() const { return p_; } + T * p_; +}; + +template< class T > +void take_raw( T* ) +{ +} +#if gsl_HAVE( UNIQUE_PTR ) +template< class T > +void take_unique_by_val( std::unique_ptr<T> ) +{ +} +template< class T > +void take_unique_by_ref( std::unique_ptr<T> const & ) +{ +} +#endif +#if gsl_HAVE( SHARED_PTR ) +template< class T > +void take_shared_by_val( std::shared_ptr<T> ) +{ +} +template< class T > +void take_shared_by_ref( std::shared_ptr<T> const & ) +{ +} +template< class T > +struct ExplicitFromShared +{ + explicit ExplicitFromShared( std::shared_ptr<T> const & ) + { + } +}; +#endif + +} // anonymous namespace + +namespace nonlocal +{ + struct S { char c; int i; }; +} + +CASE( "not_null<>: Disallows default construction (define gsl_CONFIG_CONFIRMS_COMPILATION_ERRORS)" ) +{ +#if gsl_CONFIG( CONFIRMS_COMPILATION_ERRORS ) + not_null< int* > p; +#endif +} + +CASE( "not_null<>: Disallows construction from nullptr_t, NULL or 0 (define gsl_CONFIG_CONFIRMS_COMPILATION_ERRORS)" ) +{ +#if gsl_CONFIG( CONFIRMS_COMPILATION_ERRORS ) +# if gsl_HAVE( NULLPTR ) + not_null< int* > p( nullptr ); +# endif + not_null< int* > q( NULL ); + not_null< std::vector<char>* > r( 0 ); +#endif +} + +CASE( "not_null<>: Disallows construction from a unique pointer to underlying type (define gsl_CONFIG_CONFIRMS_COMPILATION_ERRORS)" ) +{ +#if gsl_CONFIG( CONFIRMS_COMPILATION_ERRORS ) +# if gsl_HAVE( UNIQUE_PTR ) + std::unique_ptr< int > up( new int(120) ); + not_null< int* > p4( up ); +# endif +#endif +} + +CASE( "not_null<>: Layout is compatible to underlying type" ) +{ +#if gsl_HAVE( TYPE_TRAITS ) + static_assert( sizeof( not_null< int* > ) == sizeof( int* ), "static assertion failed" ); +# if gsl_HAVE( UNIQUE_PTR ) + static_assert( sizeof( not_null< unique_ptr< int > > ) == sizeof( unique_ptr< int > ), "static assertion failed" ); +# endif // gsl_HAVE( UNIQUE_PTR ) +# if gsl_HAVE( SHARED_PTR ) + static_assert( sizeof( not_null< shared_ptr< int > > ) == sizeof( shared_ptr< int > ), "static assertion failed" ); +# endif // gsl_HAVE( SHARED_PTR ) +#endif +} + +CASE( "not_null<>: Convertibility is correctly reported by type traits" ) +{ +#if gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( UNIQUE_PTR ) && !gsl_BETWEEN( gsl_COMPILER_MSVC_VERSION, 1, 120 ) + + // Permit conversion to underlying type. + static_assert( std::is_convertible< not_null< int* >, int* >::value, "static assertion failed" ); + static_assert( std::is_convertible< not_null< int* >, not_null< int* > >::value, "static assertion failed" ); +# if gsl_CONFIG( NOT_NULL_EXPLICIT_CTOR ) + static_assert( !std::is_convertible< int*, not_null< int* > >::value, "static assertion failed" ); +# endif + + // Permit conversion to underlying type with implicit upcasts. + static_assert( std::is_convertible< not_null< MyDerived* >, MyBase* >::value, "static assertion failed" ); + static_assert( std::is_convertible< not_null< MyDerived* >, not_null< MyBase* > >::value, "static assertion failed" ); +# if gsl_CONFIG( NOT_NULL_EXPLICIT_CTOR ) + static_assert( !std::is_convertible< MyDerived*, not_null< MyBase* > >::value, "static assertion failed" ); +# endif + + // Permit conversion to underlying type with implicit upcasts for move-only types. +# if gsl_HAVE( FUNCTION_REF_QUALIFIER ) + static_assert( std::is_convertible< not_null< std::unique_ptr< MyDerived > >, std::unique_ptr< MyBase > >::value, "static assertion failed" ); + static_assert( !std::is_convertible< not_null< std::unique_ptr< MyBase > >, std::unique_ptr< MyDerived > >::value, "static assertion failed" ); +# endif + + // Permit implicit upcasts for move-only types. + static_assert( std::is_convertible< not_null< std::unique_ptr< MyDerived > >, not_null< std::unique_ptr< MyBase > > >::value, "static assertion failed" ); +# if gsl_CONFIG( NOT_NULL_EXPLICIT_CTOR ) + static_assert( !std::is_convertible< std::unique_ptr< MyDerived >, not_null< std::unique_ptr< MyBase > > >::value, "static assertion failed" ); +# endif + + // `unique_ptr<T>` and `shared_ptr<T>` have explicit constructors for `T*` arguments; do not allow implicit conversion. +# if !gsl_BETWEEN( gsl_COMPILER_CLANG_VERSION, 1, 400 ) && !gsl_BETWEEN( gsl_COMPILER_APPLECLANG_VERSION, 1, 1001 ) + static_assert( !std::is_convertible< int*, not_null< std::unique_ptr< int > > >::value, "static assertion failed" ); + static_assert( !std::is_convertible< int*, not_null< std::shared_ptr< int > > >::value, "static assertion failed" ); +# endif + + // Do not permit implicit downcasts for move-only types, with or without conversion. +# if !gsl_BETWEEN( gsl_COMPILER_CLANG_VERSION, 1, 400 ) && !gsl_BETWEEN( gsl_COMPILER_APPLECLANG_VERSION, 1, 1001 ) + static_assert( !std::is_convertible< not_null< std::unique_ptr< MyBase > >, not_null< std::unique_ptr< MyDerived > > >::value, "static assertion failed" ); + static_assert( !std::is_convertible< std::unique_ptr< MyBase >, not_null< std::unique_ptr< MyDerived > > >::value, "static assertion failed" ); +# endif + + static_assert( !std::is_convertible< not_null < int* >, bool >::value, "static assertion failed" ); + static_assert( !std::is_convertible< not_null < std::unique_ptr< int > >, bool >::value, "static assertion failed" ); + static_assert( !std::is_convertible< not_null < std::shared_ptr< int > >, bool >::value, "static assertion failed" ); +#endif // gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( UNIQUE_PTR ) && !gsl_BETWEEN( gsl_COMPILER_MSVC_VERSION, 1, 120 ) +} + +CASE( "not_null<>: Copyability and assignability are correctly reported by type traits" ) +{ +#if gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( UNIQUE_PTR ) && !gsl_BETWEEN( gsl_COMPILER_MSVC_VERSION, 1, 140 ) + // Permit copy construction and assignment for raw pointers. + static_assert( std::is_copy_constructible< not_null< int* > >::value, "static assertion failed" ); + static_assert( std::is_copy_assignable< not_null< int* > >::value, "static assertion failed" ); + + // Do not permit copy construction and assignment for move-only types. + static_assert( !std::is_copy_constructible< not_null< std::unique_ptr< int > > >::value, "static assertion failed" ); +# if !gsl_BETWEEN( gsl_COMPILER_APPLECLANG_VERSION, 1, 900 ) + static_assert( !std::is_copy_assignable< not_null< std::unique_ptr< int > > >::value, "static assertion failed" ); +# endif + + // Permit explicit construction of underlying smart pointer from raw pointer type, using the smart pointer's explicit constructor. + static_assert( std::is_constructible< not_null< std::unique_ptr< int > >, int* >::value, "static assertion failed" ); + static_assert( std::is_constructible< not_null< std::shared_ptr< int > >, int* >::value, "static assertion failed" ); + + // Permit explicit construction from underlying pointer. + static_assert( std::is_constructible< not_null< MyBase* >, MyDerived* >::value, "static assertion failed" ); +# if gsl_CONFIG( NOT_NULL_EXPLICIT_CTOR ) + static_assert( !std::is_assignable< not_null< MyBase* >&, MyDerived* >::value, "static assertion failed" ); +# endif + + // Do not permit conversion to subclass pointer. + static_assert( !std::is_constructible< MyDerived*, not_null< MyBase* > >::value, "static assertion failed" ); +# if !( defined( __NVCC__ ) && gsl_BETWEEN( gsl_COMPILER_GNUC_VERSION, 800, 900 ) ) // oddly specific bug workaround + static_assert( !std::is_assignable< MyDerived*&, not_null< MyBase* > >::value, "static assertion failed" ); +# endif + + // Permit construction and assignment from subclass pointer. + static_assert( std::is_constructible< not_null< std::unique_ptr< MyBase > >, std::unique_ptr< MyDerived > >::value, "static assertion failed" ); +# if gsl_CONFIG( NOT_NULL_EXPLICIT_CTOR ) && !gsl_BETWEEN( gsl_COMPILER_APPLECLANG_VERSION, 1, 900 ) + static_assert( !std::is_assignable< not_null< std::unique_ptr< MyBase > >&, std::unique_ptr< MyDerived > >::value, "static assertion failed" ); +# endif + + // Do not permit copy construction and assignment from move-only subclass pointer. + static_assert( !std::is_constructible< not_null< std::unique_ptr< MyBase > >, std::unique_ptr< MyDerived > const & >::value, "static assertion failed" ); +# if !gsl_BETWEEN( gsl_COMPILER_APPLECLANG_VERSION, 1, 900 ) + static_assert( !std::is_assignable< not_null< std::unique_ptr< MyBase > >&, std::unique_ptr< MyDerived > const & >::value, "static assertion failed" ); +# endif + + // Permit construction and assignment from `not_null<>` with subclass pointer. + static_assert( std::is_constructible< not_null< std::unique_ptr< MyBase > >, not_null< std::unique_ptr< MyDerived > > >::value, "static assertion failed" ); + static_assert( std::is_assignable< not_null< std::unique_ptr< MyBase > >&, not_null< std::unique_ptr< MyDerived > > >::value, "static assertion failed" ); + + // Do not permit copy construction and assignment from move-only `not_null<>` with subclass pointer. + static_assert( !std::is_constructible< not_null< std::unique_ptr< MyBase > >, not_null< std::unique_ptr< MyDerived > > const & >::value, "static assertion failed" ); +# if !gsl_BETWEEN( gsl_COMPILER_APPLECLANG_VERSION, 1, 900 ) + static_assert( !std::is_assignable< not_null< std::unique_ptr< MyBase > >&, not_null< std::unique_ptr< MyDerived > > const & >::value, "static assertion failed" ); +# endif + + // Permit conversion to superclass pointer. +# if gsl_HAVE( FUNCTION_REF_QUALIFIER ) + static_assert( std::is_constructible< std::unique_ptr< MyBase >, not_null< std::unique_ptr< MyDerived > > >::value, "static assertion failed" ); + static_assert( std::is_assignable< std::unique_ptr< MyBase >&, not_null< std::unique_ptr< MyDerived > > >::value, "static assertion failed" ); +# endif + + // Do not permit conversion with copy to move-only superclass pointer. + static_assert( !std::is_constructible< std::unique_ptr< MyBase >, not_null< std::unique_ptr< MyDerived > > const & >::value, "static assertion failed" ); +# if !gsl_BETWEEN( gsl_COMPILER_APPLECLANG_VERSION, 1, 900 ) + static_assert( !std::is_assignable< std::unique_ptr< MyBase >&, not_null< std::unique_ptr< MyDerived > > const & >::value, "static assertion failed" ); +# endif + + // Do not permit construction and assignment from superclass pointer. +# if !gsl_BETWEEN( gsl_COMPILER_CLANG_VERSION, 1, 400 ) && !gsl_BETWEEN( gsl_COMPILER_APPLECLANG_VERSION, 1, 1001 ) + static_assert( !std::is_constructible< not_null< std::unique_ptr< MyDerived > >, std::unique_ptr< MyBase > >::value, "static assertion failed" ); + static_assert( !std::is_assignable< not_null< std::unique_ptr< MyDerived > >&, std::unique_ptr< MyBase > >::value, "static assertion failed" ); + + static_assert( !std::is_constructible< not_null< std::unique_ptr< MyDerived > >, not_null< std::unique_ptr< MyBase > > >::value, "static assertion failed" ); + static_assert( !std::is_assignable< not_null< std::unique_ptr< MyDerived > >&, not_null< std::unique_ptr< MyBase > > >::value, "static assertion failed" ); +# endif + + // Do not permit conversion to subclass pointer. + static_assert( !std::is_constructible< std::unique_ptr< MyDerived >, not_null< std::unique_ptr< MyBase > > >::value, "static assertion failed" ); + static_assert( !std::is_assignable< std::unique_ptr< MyDerived >&, not_null< std::unique_ptr< MyBase > > >::value, "static assertion failed" ); + + // Do not permit conversion to bool + static_assert( !std::is_constructible< bool, not_null < int* > >::value, "static assertion failed"); + static_assert( !std::is_assignable< bool&, not_null < int* > >::value, "static assertion failed"); + + static_assert( !std::is_constructible< bool, not_null < std::unique_ptr< int > > >::value, "static assertion failed"); + static_assert( !std::is_assignable< bool&, not_null < std::unique_ptr< int > > >::value, "static assertion failed"); + + static_assert( !std::is_constructible< bool, not_null < std::shared_ptr< int > > >::value, "static assertion failed"); + static_assert( !std::is_assignable< bool&, not_null < std::shared_ptr< int > > >::value, "static assertion failed"); +#endif // gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( UNIQUE_PTR ) && !gsl_BETWEEN( gsl_COMPILER_MSVC_VERSION, 1, 140 ) +} + +CASE( "not_null<>: Disallows assignment from unrelated pointers (define gsl_CONFIG_CONFIRMS_COMPILATION_ERRORS)" ) +{ +#if gsl_CONFIG( CONFIRMS_COMPILATION_ERRORS ) + MyDerived derived; + not_null< MyDerived* > p( &derived ); + + not_null< Unrelated* > r( p ); + not_null< Unrelated* > s( reinterpret_cast< Unrelated* >( p ) ); +#endif +} + +CASE( "not_null<>: Terminates construction from a null pointer value (raw pointer)" ) +{ + struct F { static void blow() { int * z = gsl_nullptr; not_null<int*> p(z); } }; + + EXPECT_THROWS( F::blow() ); +} + +CASE( "not_null<>: Terminates construction from related pointer types for null pointer value (raw pointer)" ) +{ + struct F { static void blow() { MyDerived * z = gsl_nullptr; not_null<MyBase*> p(z); } }; + + EXPECT_THROWS( F::blow() ); +} + +CASE( "not_null<>: Terminates assignment from a null pointer value (raw pointer)" ) +{ + int i = 12; + not_null<int*> p( &i ); + int * z = gsl_nullptr; + + EXPECT_THROWS( p = not_null<int*>( z ) ); +} + +CASE( "not_null<>: Terminates assignment from related pointer types for null pointer value (raw pointer)" ) +{ + MyDerived * z = gsl_nullptr; + MyDerived derived; + not_null< MyBase* > p( &derived ); + + EXPECT_THROWS( p = not_null<MyDerived*>( z ) ); +} + +CASE( "not_null<>: Allows to construct from a non-null underlying pointer (raw pointer)" ) +{ + int i = 12; + + not_null< int* > p( &i ); + + EXPECT( p == &i ); +} + +CASE( "not_null<>: Returns underlying pointer with get() (raw pointer)" ) +{ +#if !gsl_CONFIG( TRANSPARENT_NOT_NULL ) + int i = 12; + not_null< int* > p( &i ); + + int* pg = p.get(); + EXPECT( pg == &i ); +#endif +} + +CASE( "not_null<>: Allows to construct from a non-null underlying pointer (raw pointer) with make_not_null()" ) +{ + int i = 12; + + not_null< int* > p = make_not_null( &i ); + + EXPECT( p == &i ); +} + +CASE( "not_null<>: Allows to construct from a non-null underlying pointer (raw pointer) with deduction guide" ) +{ +#if gsl_HAVE( DEDUCTION_GUIDES ) + int i = 12; + + not_null p( &i ); + + EXPECT( p == &i ); +#endif +} + +CASE( "not_null<>: Allows to construct a const pointer from a non-null underlying pointer (raw pointer)" ) +{ + int i = 12; + + not_null< const int* > p( &i ); + + EXPECT( p == &i ); +} + +CASE( "not_null<>: Converts to underlying pointer (raw pointer)" ) +{ + int i = 12; + not_null< int* > p( &i ); + + take_raw<int>( p ); +} + +CASE( "as_nullable: Converts to underlying pointer (raw pointer)" ) +{ + int i = 12; + not_null< int* > p( &i ); + + take_raw<int>( as_nullable( p ) ); +#if gsl_HAVE( MOVE_FORWARD ) + take_raw<int>( as_nullable( std::move( p ) ) ); +#endif +} + +CASE( "not_null<>: Allows to construct from a non-null related pointer (raw pointer)" ) +{ + MyDerived derived; + not_null< MyBase* > p( &derived ); + + EXPECT( p == &derived ); +} + +CASE( "not_null<>: Allows to construct a const pointer from a non-null related pointer (raw pointer)" ) +{ + MyDerived derived; + not_null< const MyBase* > p( &derived ); + + EXPECT( p == &derived ); +} + +CASE( "not_null<>: Allows to construct from a not_null related pointer type (raw pointer)" ) +{ + MyDerived derived; + not_null< MyDerived* > p( &derived ); + +#if gsl_CPP11_OR_GREATER + not_null< MyBase* > q = p; +#else + not_null< MyBase* > q(p); // in C++98, we cannot differentiate between implicit and explicit cases, so conversion is always explicit +#endif + + EXPECT( q == p ); +} + +CASE( "not_null<>: Allows to construct a const pointer from a not_null related pointer type (raw pointer)" ) +{ + MyDerived derived; + not_null< MyDerived* > p( &derived ); + +#if gsl_CPP11_OR_GREATER + not_null< const MyBase* > q = p; +#else + not_null< const MyBase* > q(p); // in C++98, we cannot differentiate between implicit and explicit cases, so conversion is always explicit +#endif + + EXPECT( q == p ); +} + +CASE( "not_null<>: Converts to a related pointer (raw pointer)" ) +{ + MyDerived derived; + not_null< MyDerived* > p( &derived ); + + take_raw<MyBase>( p ); +} + +CASE( "as_nullable: Converts to a related pointer (raw pointer)" ) +{ + MyDerived derived; + not_null< MyDerived* > p( &derived ); + + take_raw<MyBase>( as_nullable( p ) ); +} + +CASE( "not_null<>: Allows assignment from a not_null related pointer type (raw pointer)" ) +{ + MyDerived derived; + not_null< MyDerived* > p( &derived ); + not_null< MyBase* > q( p ); + + q = p; + + EXPECT( q == p ); +} + +CASE( "not_null<>: Allows assignment to a const pointer from a not_null related pointer type (raw pointer)" ) +{ + MyDerived derived; + not_null< MyDerived* > p( &derived ); + not_null< const MyBase* > q( p ); + + q = p; + + EXPECT( q == p ); +} + +CASE( "not_null<>: Allows indirect member access (raw pointer)" ) +{ + using namespace nonlocal; + S s = { 'a', 7 }; + not_null< S* > p( &s ); + + EXPECT( p->c == 'a' ); + EXPECT( p->i == 7 ); +} + +CASE( "not_null<>: Allows dereferencing (raw pointer)" ) +{ + int i = 12; + not_null< int* > p( &i ); + + EXPECT( *p == i ); +} + +CASE( "not_null<>: Allows to check whether object is valid (raw pointer)" ) +{ + int i = 12; + not_null< int* > p( &i ); + + EXPECT( gsl_lite::is_valid( p ) ); + +#if gsl_HAVE( MOVE_FORWARD ) + not_null< int* > q( std::move( p ) ); + + EXPECT( gsl_lite::is_valid( p ) ); // for raw pointers, moving `not_null<>` just makes a copy + EXPECT( gsl_lite::is_valid( q ) ); +#endif +} + +#if gsl_HAVE( MOVE_FORWARD ) +template< class T > +void move_to( T& dest, T& src ) +{ + dest = std::move( src ); +} +#endif // gsl_HAVE( MOVE_FORWARD ) + +#if gsl_HAVE( SHARED_PTR ) +CASE( "not_null<>: Terminates swap of a moved-from value (shared_ptr)" ) +{ + shared_ptr< int > pi = std::make_shared< int >( 12 ); + not_null< shared_ptr< int > > p1( pi ); + not_null< shared_ptr< int > > p2( std::move( p1 ) ); + + EXPECT_THROWS( swap( p1, p2 ) ); + EXPECT_THROWS( swap( p2, p1 ) ); +} + +CASE( "not_null<>: Tolerates self-move-assignment of a moved-from value (shared_ptr)" ) +{ + shared_ptr< int > pi = std::make_shared< int >( 12 ); + not_null< shared_ptr< int > > p1( pi ); + not_null< shared_ptr< int > > p2( std::move( p1 ) ); + + EXPECT_NO_THROW( move_to(p1, p1 ) ); // use extra indirection to suppress compiler warning about explicit self-move +} + +CASE( "not_null<>: Terminates self-swap of a moved-from value (shared_ptr)" ) +{ + shared_ptr< int > pi = std::make_shared< int >( 12 ); + not_null< shared_ptr< int > > p1( pi ); + not_null< shared_ptr< int > > p2( std::move( p1 ) ); + + EXPECT_THROWS( swap( p1, p1 ) ); +} + +CASE( "not_null<>: Terminates construction from a null pointer value (shared_ptr)" ) +{ + struct F { static void blow() { shared_ptr< int > z = gsl_nullptr; not_null< shared_ptr< int > > p(z); } }; + + EXPECT_THROWS( F::blow() ); +} + +CASE( "not_null<>: Terminates construction from related pointer types for null pointer value (shared_ptr)" ) +{ + struct F { static void blow() { shared_ptr< MyDerived > z = gsl_nullptr; not_null< shared_ptr< MyBase > > p(z); } }; + + EXPECT_THROWS( F::blow() ); +} + +CASE( "not_null<>: Terminates assignment from a null pointer value (shared_ptr)" ) +{ + not_null< shared_ptr< int > > p( std::make_shared< int >(12) ); + shared_ptr< int > z = gsl_nullptr; + + EXPECT_THROWS( p = not_null< shared_ptr< int > >( z ) ); +} + +CASE( "not_null<>: Terminates assignment from related pointer types for null pointer value (shared_ptr)" ) +{ + shared_ptr< MyDerived > z = gsl_nullptr; + not_null< shared_ptr< MyBase > > p( std::make_shared< MyDerived >() ); + + EXPECT_THROWS( p = not_null< shared_ptr< MyDerived > >( z ) ); +} + +CASE( "not_null<>: Terminates propagation of a moved-from value (shared_ptr)" ) +{ + shared_ptr< int > pi = std::make_shared< int >(12); + not_null< shared_ptr< int > > p( std::move( pi ) ); + not_null< shared_ptr< int > > q( std::move( p ) ); + + EXPECT_THROWS( not_null< shared_ptr< int > > v( p ) ); + EXPECT_THROWS( not_null< shared_ptr< int > > v( std::move( p ) ) ); + EXPECT_THROWS( q = p ); + EXPECT_THROWS( q = std::move( p ) ); +} + +CASE( "not_null<>: Allows self-swap (shared_ptr)" ) +{ + shared_ptr< int > pi = std::make_shared< int >( 12 ); + not_null< shared_ptr< int > > p( pi ); + + EXPECT_NO_THROW( swap( p, p ) ); + EXPECT( p == pi ); +} + +CASE( "not_null<>: Allows swap (shared_ptr)" ) +{ + shared_ptr< int > pi1 = std::make_shared< int >( 12 ); + shared_ptr< int > pi2 = std::make_shared< int >( 34 ); + not_null< shared_ptr< int > > p1( pi1 ); + not_null< shared_ptr< int > > p2( pi2 ); + + EXPECT_NO_THROW( swap( p1, p2 ) ); + EXPECT( p1 == pi2 ); + EXPECT( p2 == pi1 ); +} + +CASE( "not_null<>: Allows to construct from a non-null underlying pointer (shared_ptr)" ) +{ + shared_ptr< int > pi = std::make_shared< int >(12); + not_null< shared_ptr< int > > p( pi ); + + EXPECT( p == pi ); +} + +CASE( "not_null<>: Allows to construct from a non-null raw pointer with explicit conversion (shared_ptr)" ) +{ + int* i = new int(12); + not_null< shared_ptr< int > > p( i ); +} + +CASE( "not_null<>: Returns underlying pointer or raw pointer with get() (shared_ptr)" ) +{ + shared_ptr< int > pi = std::make_shared< int >(12); + not_null< shared_ptr< int > > p( pi ); + +#if gsl_CONFIG( TRANSPARENT_NOT_NULL ) + int* pg = p.get(); + EXPECT( pg == pi.get() ); +#else + shared_ptr< int > const & pg = p.get(); + EXPECT( pg == pi ); +#endif +} + +CASE( "not_null<>: Allows to move from a not_null pointer to an underlying pointer (shared_ptr)" ) +{ +#if gsl_HAVE( FUNCTION_REF_QUALIFIER ) + shared_ptr< int > pi = std::make_shared< int >(12); + int* raw(pi.get()); + + not_null< shared_ptr< int > > p ( std::move(pi) ); // There... + pi = std::move(p); // ...and back again. + + EXPECT_THROWS( (void) *p ); + EXPECT( pi.get() == raw ); +#endif +} + +CASE( "as_nullable: Allows to move from a not_null pointer to an underlying pointer (shared_ptr)" ) +{ + shared_ptr< int > pi = std::make_shared< int >(12); + int* raw(pi.get()); + + not_null< shared_ptr< int > > p ( std::move(pi) ); // There... + pi = as_nullable( std::move(p) ); // ...and back again. + + EXPECT_THROWS( (void) *p ); + EXPECT( pi.get() == raw ); +} + +CASE( "not_null<>: Allows to construct from a non-null underlying pointer (shared_ptr) with make_not_null()" ) +{ + shared_ptr< int > pi = std::make_shared< int >(12); + + not_null< shared_ptr< int > > p = make_not_null( pi ); + + EXPECT( p == pi ); +} + +CASE( "not_null<>: Allows to construct from a non-null underlying pointer (shared_ptr) with deduction guide" ) +{ +#if gsl_HAVE( DEDUCTION_GUIDES ) + shared_ptr< int > pi = std::make_shared< int >(12); + + not_null p( pi ); + + EXPECT( p == pi ); +#endif +} + +CASE( "not_null<>: Allows to construct a const pointer from a non-null underlying pointer (shared_ptr)" ) +{ + shared_ptr< int > pi = std::make_shared< int >(12); + not_null< shared_ptr< const int > > p( pi ); + + EXPECT( p == pi ); +} + +CASE( "not_null<>: Converts to underlying pointer (shared_ptr)" ) +{ + shared_ptr< int > pi = std::make_shared< int >(); + not_null< shared_ptr< int > > p( pi ); + + take_shared_by_val<int>( p ); + take_shared_by_ref<int>( p ); +} + +CASE( "as_nullable: Converts to underlying pointer (shared_ptr)" ) +{ + shared_ptr< int > pi = std::make_shared< int >(); + not_null< shared_ptr< int > > p( pi ); + + take_shared_by_val<int>( as_nullable( p ) ); + take_shared_by_ref<int>( as_nullable( p ) ); +} + +CASE( "as_nullable: Terminates for moved-from pointer (shared_ptr)" ) +{ + shared_ptr< int > pi = std::make_shared< int >(); + not_null< shared_ptr< int > > p( pi ); + not_null< shared_ptr< int > > p2( std::move( p ) ); + + EXPECT_THROWS( (void) as_nullable( p ) ); +} + +CASE( "not_null<>: Allows to construct from a non-null related pointer (shared_ptr)" ) +{ + shared_ptr< MyDerived > pderived = std::make_shared< MyDerived >(); + not_null< shared_ptr< MyBase > > p( pderived ); + + EXPECT( p == pderived ); +} + +CASE( "not_null<>: Allows to construct a const pointer from a non-null related pointer (shared_ptr)" ) +{ + shared_ptr< MyDerived > pderived = std::make_shared< MyDerived >(); + not_null< shared_ptr< const MyBase > > p( pderived ); + + EXPECT( p == pderived ); +} + +CASE( "not_null<>: Allows to construct from a not_null related pointer type (shared_ptr)" ) +{ + shared_ptr< MyDerived > pderived = std::make_shared< MyDerived >(); + not_null< shared_ptr< MyDerived > > p( pderived ); + +#if gsl_CPP11_OR_GREATER + not_null< shared_ptr< MyBase > > q = p; +#else + not_null< shared_ptr< MyBase > > q(p); // in C++98, we cannot differentiate between implicit and explicit cases, so conversion is always explicit +#endif + + EXPECT( q == p ); +} + +CASE( "not_null<>: Allows to construct a const pointer from a not_null related pointer type (shared_ptr)" ) +{ + shared_ptr< MyDerived > pderived = std::make_shared< MyDerived >(); + not_null< shared_ptr< MyDerived > > p( pderived ); + +#if gsl_CPP11_OR_GREATER + not_null< shared_ptr< const MyBase > > q = p; +#else + not_null< shared_ptr< const MyBase > > q(p); // in C++98, we cannot differentiate between implicit and explicit cases, so conversion is always explicit +#endif + + EXPECT( q == p ); +} + +CASE( "not_null<>: Converts to a related pointer (shared_ptr)" ) +{ + shared_ptr< MyDerived > pderived = std::make_shared< MyDerived >(); + not_null< shared_ptr< MyDerived > > p( pderived ); + + take_shared_by_val<MyBase>( p ); + take_shared_by_ref<MyBase>( p ); +} + +CASE( "as_nullable: Converts to a related pointer (shared_ptr)" ) +{ + shared_ptr< MyDerived > pderived = std::make_shared< MyDerived >(); + not_null< shared_ptr< MyDerived > > p( pderived ); + + take_shared_by_val<MyBase>( as_nullable(p) ); + take_shared_by_ref<MyBase>( as_nullable(p) ); +} + +CASE( "not_null<>: Allows assignment from a not_null related pointer type (shared_ptr)" ) +{ + shared_ptr< MyDerived > pderived = std::make_shared< MyDerived >(); + not_null< shared_ptr< MyDerived > > p( pderived ); + not_null< shared_ptr< MyBase > > q( p ); + + q = p; + + EXPECT( q == p ); +} + +CASE( "not_null<>: Allows assignment to a const pointer from a not_null related pointer type (shared_ptr)" ) +{ + shared_ptr< MyDerived > pderived = std::make_shared< MyDerived >(); + not_null< shared_ptr< MyDerived > > p( pderived ); + not_null< shared_ptr< const MyBase > > q( p ); + + q = p; + + EXPECT( q == p ); +} + +CASE( "not_null<>: Allows indirect member access (shared_ptr)" ) +{ + using namespace nonlocal; + S s = { 'a', 7 }; + not_null< shared_ptr< S > > p( std::make_shared< S >(s) ); + + EXPECT( p->c == 'a' ); + EXPECT( p->i == 7 ); +} + +CASE( "not_null<>: Allows dereferencing (shared_ptr)" ) +{ + shared_ptr< int > pi = std::make_shared< int >(12); + not_null< shared_ptr< int > > p( pi ); + + EXPECT( *p == *pi ); +} + +CASE( "not_null<>: Allows to check whether object is valid (shared_ptr)" ) +{ + shared_ptr< int > pi = std::make_shared< int >(12); + not_null< shared_ptr< int > > p( pi ); + + EXPECT( gsl_lite::is_valid( p ) ); + + not_null< shared_ptr< int > > q( std::move( p ) ); + + EXPECT_NOT( gsl_lite::is_valid( p ) ); + EXPECT( gsl_lite::is_valid( q ) ); +} + +#endif // gsl_HAVE( SHARED_PTR ) + +#if gsl_HAVE( UNIQUE_PTR ) + +template<typename T> +unique_ptr<T> my_make_unique() +{ + return unique_ptr<T>(new T()); +} + +template<typename T, typename Arg> +unique_ptr<T> my_make_unique(Arg&& arg) +{ + return unique_ptr<T>(new T(std::forward<Arg>(arg))); +} + +CASE( "not_null<>: Terminates swap of a moved-from value (unique_ptr)" ) +{ + unique_ptr< int > pi = my_make_unique< int >( 12 ); + not_null< unique_ptr< int > > p1( std::move( pi ) ); + not_null< unique_ptr< int > > p2( std::move( p1 ) ); + + EXPECT_THROWS( swap( p1, p2 ) ); + EXPECT_THROWS( swap( p2, p1 ) ); +} + +CASE( "not_null<>: Tolerates self-move-assignment of a moved-from value (unique_ptr)" ) +{ + unique_ptr< int > pi = my_make_unique< int >( 12 ); + not_null< unique_ptr< int > > p1( std::move( pi ) ); + not_null< unique_ptr< int > > p2( std::move( p1 ) ); + + EXPECT_NO_THROW( move_to(p1, p1 ) ); // use extra indirection to suppress compiler warning about explicit self-move +} + +CASE( "not_null<>: Terminates self-swap of a moved-from value (unique_ptr)" ) +{ + unique_ptr< int > pi = my_make_unique< int >( 12 ); + not_null< unique_ptr< int > > p1( std::move( pi ) ); + not_null< unique_ptr< int > > p2( std::move( p1 ) ); + + EXPECT_THROWS( swap(p1, p1) ); +} + +CASE( "not_null<>: Terminates construction from a null pointer value (unique_ptr)" ) +{ + struct F { static void blow() { unique_ptr< int > z = gsl_nullptr; not_null< unique_ptr< int > > p(std::move(z)); } }; + + EXPECT_THROWS( F::blow() ); +} + +CASE( "not_null<>: Terminates construction from related pointer types for null pointer value (unique_ptr)" ) +{ + struct F { static void blow() { unique_ptr< MyDerived > z = gsl_nullptr; not_null< unique_ptr< MyBase > > p(std::move(z)); } }; + + EXPECT_THROWS( F::blow() ); +} + +CASE( "not_null<>: Terminates assignment from a null pointer value (unique_ptr)" ) +{ + not_null< unique_ptr< int > > p( my_make_unique< int >(12) ); + unique_ptr< int > z = gsl_nullptr; + + EXPECT_THROWS( p = not_null< unique_ptr< int > >( std::move(z) ) ); +} + +CASE( "not_null<>: Terminates assignment from related pointer types for null pointer value (unique_ptr)" ) +{ + unique_ptr< MyDerived > z = gsl_nullptr; + not_null< unique_ptr< MyBase > > p( my_make_unique< MyDerived >() ); + + EXPECT_THROWS( p = not_null< unique_ptr< MyDerived > >( std::move(z) ) ); +} + +CASE( "not_null<>: Terminates propagation of a moved-from value (unique_ptr)" ) +{ + unique_ptr< int > pi = my_make_unique< int >(12); + not_null< unique_ptr< int > > p( std::move( pi ) ); + not_null< unique_ptr< int > > q( std::move( p ) ); + + EXPECT_THROWS( not_null< unique_ptr< int > >( std::move( p ) ) ); + EXPECT_THROWS( q = std::move( p ) ); +} + +CASE( "not_null<>: Allows self-swap (unique_ptr)" ) +{ + unique_ptr< int > pi = my_make_unique< int >( 12 ); + int* raw( pi.get() ); + not_null< unique_ptr< int > > p( std::move( pi ) ); + + EXPECT_NO_THROW( swap( p, p ) ); + EXPECT( &*p == raw ); +} + +CASE( "not_null<>: Allows swap (unique_ptr)" ) +{ + unique_ptr< int > pi1 = my_make_unique< int >( 12 ); + unique_ptr< int > pi2 = my_make_unique< int >( 34 ); + int* raw1( pi1.get() ); + int* raw2( pi2.get() ); + not_null< unique_ptr< int > > p1( std::move( pi1 ) ); + not_null< unique_ptr< int > > p2( std::move( pi2 ) ); + + EXPECT_NO_THROW( swap( p1, p2 ) ); + EXPECT( &*p1 == raw2 ); + EXPECT( &*p2 == raw1 ); +} + +CASE( "not_null<>: Allows to construct from a non-null underlying pointer (unique_ptr)" ) +{ + unique_ptr< int > pi = my_make_unique< int >(12); + int* raw(pi.get()); + not_null< unique_ptr< int > > p( std::move(pi) ); + + EXPECT( &*p == raw ); +} + +CASE( "not_null<>: Allows to construct from a non-null raw pointer with explicit conversion (unique_ptr)" ) +{ + int* i = new int(12); + not_null< unique_ptr< int > > p( i ); +} + +CASE( "not_null<>: Returns underlying pointer or raw pointer with get() (unique_ptr)" ) +{ +#if gsl_CONFIG( TRANSPARENT_NOT_NULL ) || gsl_CONFIG( NOT_NULL_GET_BY_CONST_REF ) + unique_ptr< int > pi = my_make_unique< int >(12); + int* raw(pi.get()); + not_null< unique_ptr< int > > p( std::move(pi) ); + +# if gsl_CONFIG( TRANSPARENT_NOT_NULL ) + int* pg = p.get(); + EXPECT( pg == raw ); +# else // gsl_CONFIG( NOT_NULL_GET_BY_CONST_REF ) + int* pg = p.get().get(); + EXPECT( pg == raw ); +# endif +#endif +} + +CASE( "not_null<>: Allows to move from a not_null pointer to an underlying pointer (unique_ptr)" ) +{ +#if gsl_HAVE( FUNCTION_REF_QUALIFIER ) + unique_ptr< int > pi = my_make_unique< int >(12); + int* raw(pi.get()); + + not_null< unique_ptr< int > > p ( std::move(pi) ); // There... + pi = std::move(p); // ...and back again. + + EXPECT_THROWS( (void) *p ); + EXPECT( pi.get() == raw ); +#endif +} + +CASE( "as_nullable: Allows to move from a not_null pointer to an underlying pointer (unique_ptr)" ) +{ + unique_ptr< int > pi = my_make_unique< int >(12); + int* raw(pi.get()); + + not_null< unique_ptr< int > > p ( std::move(pi) ); // There... + pi = as_nullable( std::move(p) ); // ...and back again. + + EXPECT_THROWS( (void) *p ); + EXPECT( pi.get() == raw ); +} + +CASE( "not_null<>: Allows to move to a related pointer from a not_null pointer (unique_ptr)" ) +{ +#if gsl_HAVE( FUNCTION_REF_QUALIFIER ) + unique_ptr< MyDerived > pderived = my_make_unique< MyDerived >(); + MyDerived* raw(pderived.get()); + not_null< unique_ptr< MyDerived > > p ( std::move(pderived) ); + unique_ptr< MyBase > pbase = std::move(p); + + EXPECT_THROWS( (void) *p ); + EXPECT( pbase.get() == raw ); +#endif +} + +CASE( "as_nullable: Allows to move to a related pointer from a not_null pointer (unique_ptr)" ) +{ + unique_ptr< MyDerived > pderived = my_make_unique< MyDerived >(); + MyDerived* raw(pderived.get()); + not_null< unique_ptr< MyDerived > > p ( std::move(pderived) ); + unique_ptr< MyBase > pbase = as_nullable( std::move(p) ); + + EXPECT_THROWS( (void) *p ); + EXPECT( pbase.get() == raw ); +} + +CASE( "not_null<>: Allows to construct from a non-null underlying pointer (unique_ptr) with make_not_null()" ) +{ + unique_ptr< int > pi = my_make_unique< int >(12); + int* raw(pi.get()); + + not_null< unique_ptr< int > > p = make_not_null( std::move(pi) ); + + EXPECT( &*p == raw ); +} + +CASE( "not_null<>: Allows to construct from a non-null underlying pointer (unique_ptr) with deduction guide" ) +{ +#if gsl_HAVE( DEDUCTION_GUIDES ) + unique_ptr< int > pi = my_make_unique< int >(12); + int* raw(pi.get()); + + not_null p( std::move(pi) ); + + EXPECT( &*p == raw ); +#endif +} + +CASE( "not_null<>: Allows to construct a const pointer from a non-null underlying pointer (unique_ptr)" ) +{ + unique_ptr< int > pi = my_make_unique< int >(12); + int* raw(pi.get()); + not_null< unique_ptr< const int > > p( std::move(pi) ); + + EXPECT( &*p == raw ); +} + +CASE( "not_null<>: Converts to underlying pointer (unique_ptr)" ) +{ +#if gsl_HAVE( FUNCTION_REF_QUALIFIER ) + unique_ptr< int > pi = my_make_unique< int >(); + not_null< unique_ptr< int > > p( std::move(pi) ); + + take_unique_by_val<int>( std::move(p) ); + //take_unique_by_ref<int>( p ); // We sacrifice the ability to convert to `unique_ptr<> const &`, cf. comment regarding conversion operators in gsl-lite.hpp. +#endif +} + +CASE( "as_nullable: Converts to underlying pointer (unique_ptr)" ) +{ + unique_ptr< int > pi = my_make_unique< int >(); + not_null< unique_ptr< int > > p( std::move(pi) ); + + take_unique_by_ref<int>( as_nullable( p ) ); + take_unique_by_val<int>( as_nullable( std::move( p ) ) ); +} + +CASE( "as_nullable: Terminates for moved-from pointer (unique_ptr)" ) +{ + unique_ptr< int > pi = my_make_unique< int >(); + not_null< unique_ptr< int > > p( std::move( pi ) ); + not_null< unique_ptr< int > > p2( std::move( p ) ); + + EXPECT_THROWS( (void) as_nullable( p ) ); +} + +CASE( "not_null<>: Allows to construct from a non-null related pointer (unique_ptr)" ) +{ + unique_ptr< MyDerived > pderived = my_make_unique< MyDerived >(); + MyDerived* raw(pderived.get()); + not_null< unique_ptr< MyBase > > p( std::move(pderived) ); + + EXPECT( &*p == raw ); +} + +CASE( "not_null<>: Allows to construct a const pointer from a non-null related pointer (unique_ptr)" ) +{ + unique_ptr< MyDerived > pderived = my_make_unique< MyDerived >(); + MyDerived* raw(pderived.get()); + not_null< unique_ptr< const MyBase > > p( std::move(pderived) ); + + EXPECT( &*p == raw ); +} + +CASE( "not_null<>: Allows to construct from a not_null related pointer type (unique_ptr)" ) +{ + unique_ptr< MyDerived > pderived = my_make_unique< MyDerived >(); + MyDerived* raw(pderived.get()); + not_null< unique_ptr< MyDerived > > p( std::move(pderived) ); + +#if gsl_CPP11_OR_GREATER + not_null< unique_ptr< MyBase > > q = std::move(p); +#else + not_null< unique_ptr< MyBase > > q(std::move(p)); // in C++98, we cannot differentiate between implicit and explicit cases, so conversion is always explicit +#endif + + EXPECT( &*q == raw ); +} + +CASE( "not_null<>: Allows to construct a const pointer from a not_null related pointer type (unique_ptr)" ) +{ + unique_ptr< MyDerived > pderived = my_make_unique< MyDerived >(); + MyDerived* raw(pderived.get()); + not_null< unique_ptr< MyDerived > > p( std::move(pderived) ); + +#if gsl_CPP11_OR_GREATER + not_null< unique_ptr< const MyBase > > q = std::move(p); +#else + not_null< unique_ptr< const MyBase > > q(std::move(p)); // in C++98, we cannot differentiate between implicit and explicit cases, so conversion is always explicit +#endif + + EXPECT( &*q == raw ); +} + +CASE( "not_null<>: Converts to a related pointer (unique_ptr)" ) +{ +#if gsl_HAVE( FUNCTION_REF_QUALIFIER ) + unique_ptr< MyDerived > pderived = my_make_unique< MyDerived >(); + not_null< unique_ptr< MyDerived > > p( std::move(pderived) ); + + take_unique_by_val<MyBase>( std::move(p) ); + //take_unique_by_ref<MyBase>( p ); // We sacrifice the ability to convert to `unique_ptr<> const &`, cf. comment regarding conversion operators in gsl-lite.hpp. +#endif +} + +CASE( "as_nullable: Converts to a related pointer (unique_ptr)" ) +{ + unique_ptr< MyDerived > pderived = my_make_unique< MyDerived >(); + not_null< unique_ptr< MyDerived > > p( std::move(pderived) ); + + take_unique_by_val<MyBase>( as_nullable( std::move(p) ) ); +} + +CASE( "not_null<>: Allows assignment from a not_null related pointer type (unique_ptr)" ) +{ + unique_ptr< MyDerived > pderived = my_make_unique< MyDerived >(); + MyDerived* raw(pderived.get()); + not_null< unique_ptr< MyDerived > > p( std::move(pderived) ); + not_null< unique_ptr< MyBase > > q( my_make_unique< MyBase >() ); + + q = std::move(p); + + EXPECT( &*q == raw ); +} + +CASE( "not_null<>: Allows assignment to a const pointer from a not_null related pointer type (unique_ptr)" ) +{ + unique_ptr< MyDerived > pderived = my_make_unique< MyDerived >(); + MyDerived* raw(pderived.get()); + not_null< unique_ptr< MyDerived > > p( std::move(pderived) ); + not_null< unique_ptr< const MyBase > > q( my_make_unique< MyBase >() ); + + q = std::move(p); + + EXPECT( &*q == raw ); +} + +CASE( "not_null<>: Allows indirect member access (unique_ptr)" ) +{ + using namespace nonlocal; + S s = { 'a', 7 }; + not_null< unique_ptr< S > > p( my_make_unique< S >(s) ); + + EXPECT( p->c == 'a' ); + EXPECT( p->i == 7 ); +} + +CASE( "not_null<>: Allows dereferencing (unique_ptr)" ) +{ + int i = 12; + unique_ptr< int > pi = my_make_unique< int >(12); + not_null< unique_ptr< int > > p( std::move(pi) ); + + EXPECT( *p == i ); +} + +CASE( "not_null<>: Allows to check whether object is valid (unique_ptr)" ) +{ + unique_ptr< int > pi = my_make_unique< int >( 12 ); + not_null< unique_ptr< int > > p( std::move(pi) ); + + EXPECT( gsl_lite::is_valid( p ) ); + + not_null< unique_ptr< int > > q( std::move( p ) ); + + EXPECT_NOT( gsl_lite::is_valid( p ) ); + EXPECT( gsl_lite::is_valid( q ) ); +} + +#endif // gsl_HAVE( UNIQUE_PTR ) + +#if gsl_HAVE( UNIQUE_PTR ) && gsl_HAVE( SHARED_PTR ) + +CASE( "not_null<>: Allows to construct a not_null<shared_ptr<T>> from a non-null unique_ptr<T>" ) +{ + unique_ptr< int > pi = my_make_unique< int >(12); + int* raw(pi.get()); + not_null< shared_ptr< int > > p( std::move(pi) ); + + EXPECT( &*p == raw ); +} + +CASE( "not_null<>: Allows to construct a not_null<shared_ptr<const T>> from a non-null unique_ptr<T>" ) +{ + unique_ptr< int > pi = my_make_unique< int >(12); + int* raw(pi.get()); + not_null< shared_ptr< const int > > p( std::move(pi) ); + + EXPECT( &*p == raw ); +} + +CASE( "not_null<>: Allows to construct a not_null<shared_ptr<T>> from a related non-null unique_ptr<U>" ) +{ + unique_ptr< MyDerived > pderived = my_make_unique< MyDerived >(); + MyDerived* raw(pderived.get()); + not_null< shared_ptr< MyBase > > p( std::move(pderived) ); + + EXPECT( &*p == raw ); +} + +CASE( "not_null<>: Allows to construct a not_null<shared_ptr<const T>> from a related non-null unique_ptr<U>" ) +{ + unique_ptr< MyDerived > pderived = my_make_unique< MyDerived >(); + MyDerived* raw(pderived.get()); + not_null< shared_ptr< const MyBase > > p( std::move(pderived) ); + + EXPECT( &*p == raw ); +} + +CASE( "not_null<>: Allows to construct a not_null<shared_ptr<T>> from a not_null<unique_ptr<T>>" ) +{ + unique_ptr< int > pi = my_make_unique< int >(12); + int* raw(pi.get()); + not_null< unique_ptr< int > > p( std::move(pi) ); + +#if gsl_CPP11_OR_GREATER + not_null< shared_ptr< int > > q = std::move(p); +#else + not_null< shared_ptr< int > > q(std::move(p)); // in C++98, we cannot differentiate between implicit and explicit cases, so conversion is always explicit +#endif + + EXPECT( &*q == raw ); +} + +CASE( "not_null<>: Allows to convert to weak_ptr<T> from a not_null<shared_ptr<T>>" ) +{ + shared_ptr< int > pi = std::make_shared< int >(12); + int* raw(pi.get()); + not_null< shared_ptr< int > > p( std::move(pi) ); + +#if gsl_CPP11_OR_GREATER + std::weak_ptr< int > q = p; + std::vector< std::weak_ptr< int > > v; + v.emplace_back( p ); +#else + std::weak_ptr< int > q(p); // in C++98, we cannot differentiate between implicit and explicit cases, so conversion is always explicit +#endif + + EXPECT_NOT( q.expired() ); + EXPECT( q.lock().get() == raw ); +} + +// C++14 has ambiguity issues with constructors and conversion operators that were fixed in C++17, +// cf. https://github.com/gsl-lite/gsl-lite/issues/275#issuecomment-678640600. +// Also, Clang ≤ 5 may pretend to support C++17 but it still suffers from the conversion ambiguity. +#if gsl_CPP17_OR_GREATER && ! ( gsl_BETWEEN(gsl_COMPILER_CLANG_VERSION, 1, 600) || gsl_BETWEEN(gsl_COMPILER_APPLECLANG_VERSION, 1, 1000) ) +CASE( "not_null<>: Allows to convert from a not_null<shared_ptr<T>> to a user-defined type with explicit conversion constructor" ) +{ + shared_ptr< int > pi = std::make_shared< int >(12); + not_null< shared_ptr< int > > p( std::move(pi) ); + + ExplicitFromShared< int > q(p); + (void) q; +} +#endif // gsl_CPP17_OR_GREATER + +CASE( "not_null<>: Allows to construct a not_null<shared_ptr<const T>> from a not_null<unique_ptr<T>>" ) +{ + unique_ptr< int > pi = my_make_unique< int >(12); + int* raw(pi.get()); + not_null< unique_ptr< int > > p( std::move(pi) ); + +#if gsl_CPP11_OR_GREATER + not_null< shared_ptr< const int > > q = std::move(p); +#else + not_null< shared_ptr< const int > > q(std::move(p)); // in C++98, we cannot differentiate between implicit and explicit cases, so conversion is always explicit +#endif + + EXPECT( &*q == raw ); +} + +CASE( "not_null<>: Allows to construct a not_null<shared_ptr<T>> from a related not_null<unique_ptr<U>>" ) +{ + unique_ptr< MyDerived > pderived = my_make_unique< MyDerived >(); + MyDerived* raw(pderived.get()); + not_null< unique_ptr< MyDerived > > p( std::move(pderived) ); + +#if gsl_CPP11_OR_GREATER + not_null< shared_ptr< MyBase > > q = std::move(p); +#else + not_null< shared_ptr< MyBase > > q(std::move(p)); // in C++98, we cannot differentiate between implicit and explicit cases, so conversion is always explicit +#endif + + EXPECT( &*q == raw ); +} + +CASE( "not_null<>: Allows to construct a not_null<shared_ptr<const T>> from a related not_null<unique_ptr<U>>" ) +{ + unique_ptr< MyDerived > pderived = my_make_unique< MyDerived >(); + MyDerived* raw(pderived.get()); + not_null< unique_ptr< MyDerived > > p( std::move(pderived) ); + +#if gsl_CPP11_OR_GREATER + not_null< shared_ptr< const MyBase > > q = std::move(p); +#else + not_null< shared_ptr< const MyBase > > q(std::move(p)); // in C++98, we cannot differentiate between implicit and explicit cases, so conversion is always explicit +#endif + + EXPECT( &*q == raw ); +} + +CASE( "not_null<>: Allows assignment to a not_null<shared_ptr<T>> from a related not_null<unique_ptr<U>>" ) +{ + unique_ptr< MyDerived > pderived = my_make_unique< MyDerived >(); + MyDerived* raw(pderived.get()); + not_null< unique_ptr< MyDerived > > p( std::move(pderived) ); + not_null< shared_ptr< MyBase > > q( std::make_shared< MyBase >() ); + + q = std::move(p); + + EXPECT( &*q == raw ); +} + +CASE( "not_null<>: Allows assignment to a not_null<shared_ptr<const T>> from a related not_null<unique_ptr<U>>" ) +{ + unique_ptr< MyDerived > pderived = my_make_unique< MyDerived >(); + MyDerived* raw(pderived.get()); + not_null< unique_ptr< MyDerived > > p( std::move(pderived) ); + not_null< shared_ptr< const MyBase > > q( std::make_shared< MyBase >() ); + + q = std::move(p); + + EXPECT( &*q == raw ); +} + +# if gsl_HAVE( VARIADIC_TEMPLATE ) +# if !gsl_BETWEEN( gsl_COMPILER_MSVC_VERSION, 120, 130 ) // VS 2013 +CASE( "not_null<>: make_unique<T>() returns not_null<unique_ptr<T>>" ) +{ + not_null< unique_ptr< int > > p = make_unique< int >(); + unique_ptr< int > q = std::move( p ); + (void) q; + + EXPECT( q.get() != nullptr ); + +} +# endif // !gsl_BETWEEN( gsl_COMPILER_MSVC_VERSION, 120, 130 ) +CASE( "not_null<>: make_shared<T>() returns not_null<shared_ptr<T>>" ) +{ + not_null< shared_ptr< int > > p = make_shared< int >(); + shared_ptr< int > q = std::move( p ); + (void) q; + + EXPECT( q.get() != nullptr ); +} +# endif // gsl_HAVE( VARIADIC_TEMPLATE ) + +#endif // gsl_HAVE( UNIQUE_PTR ) && gsl_HAVE( SHARED_PTR ) + +CASE( "not_null<>: Allows assignment from a non-null bare recast pointer" ) +{ + MyDerived derived; + not_null< MyDerived* > p( &derived ); + + not_null< Unrelated* > t( reinterpret_cast< Unrelated* >( &*p ) ); + + EXPECT( &*p == reinterpret_cast< MyDerived* >( &*t ) ); +} + +CASE( "not_null<>: Allows implicit conversion to underlying type" ) +{ + struct F { static bool helper( not_null< int* > p ) { return *p == 12; } }; + + int i = 12; + not_null< int* > p( &i ); + + EXPECT( F::helper( p ) ); +} + +CASE( "not_null<>: Allows to construct from a non-null user-defined ref-counted type" ) +{ + int i = 12; + RefCounted< int > rp = RefCounted<int>( &i ); + + not_null< int*> p( rp ); + + EXPECT( p == &i ); +} + +namespace { + +// provide not_null pointers to compare: + +struct NotNull +{ + int vs[2]; + int * pv1; int const * pv2; + + NotNull() + : pv1( &vs[ 0 ] ), pv2( &vs[ 1 ] ) + { + vs[0] = 7; + vs[1] = 42; + } + + not_null< int * > p1() const { return not_null< int * >( pv1 ); } + not_null< int const * > p2() const { return not_null< int const * >( pv2 ); } +}; +} + +CASE( "not_null<>: Allows to compare equal to another not_null of the same type" ) +{ + NotNull _; + + EXPECT( _.p1() == _.p1() ); + EXPECT_NOT( _.p1() == _.p2() ); +} + +CASE( "not_null<>: Allows to compare unequal to another not_null of the same type" ) +{ + NotNull _; + + EXPECT( _.p1() != _.p2() ); + EXPECT_NOT( _.p1() != _.p1() ); +} + +CASE( "not_null<>: Allows to compare less than another not_null of the same type" ) +{ + NotNull _; + + EXPECT_NOT( _.p1() < _.p1() ); + EXPECT( ( _.p1() < _.p2() ) == ( _.pv1 < _.pv2 ) ); + EXPECT( ( _.p2() < _.p1() ) == ( _.pv2 < _.pv1 ) ); +} + +CASE( "not_null<>: Allows to compare less than or equal to another not_null of the same type" ) +{ + NotNull _; + + EXPECT( ( _.p1() <= _.p1() ) ); + EXPECT( ( _.p1() <= _.p2() ) == ( _.pv1 <= _.pv2 ) ); + EXPECT( ( _.p2() <= _.p1() ) == ( _.pv2 <= _.pv1 ) ); +} + +CASE( "not_null<>: Allows to compare greater than another not_null of the same type" ) +{ + NotNull _; + + EXPECT_NOT( _.p1() > _.p1() ); + EXPECT( ( _.p1() > _.p2() ) == ( _.pv1 > _.pv2 ) ); + EXPECT( ( _.p2() > _.p1() ) == ( _.pv2 > _.pv1 ) ); +} + +CASE( "not_null<>: Allows to compare greater than or equal to another not_null of the same type" ) +{ + NotNull _; + + EXPECT( _.p1() >= _.p1() ); + EXPECT( ( _.p1() >= _.p2() ) == ( _.pv1 >= _.pv2 ) ); + EXPECT( ( _.p2() >= _.p1() ) == ( _.pv2 >= _.pv1 ) ); +} + +#if gsl_STDLIB_CPP20_OR_GREATER +CASE( "not_null<>: Allows to 3-way compare with another not_null of the same type" ) +{ + NotNull _; + + EXPECT( ( _.p1() <=> _.p1() == 0 ) ); + EXPECT( ( ( _.p1() <=> _.p2() ) == ( _.pv1 <=> _.pv2 ) ) ); + EXPECT( ( ( _.p2() <=> _.p1() ) == ( _.pv2 <=> _.pv1 ) ) ); +} +#endif // gsl_STDLIB_CPP20_OR_GREATER + +// raw pointer + +CASE( "not_null<>: Allows to compare equal to a raw pointer of the same type" ) +{ + NotNull _; + + EXPECT( _.p1() == _.pv1 ); + EXPECT_NOT( _.p1() == _.pv2 ); +} + +CASE( "not_null<>: Allows to compare unequal to a raw pointer of the same type" ) +{ + NotNull _; + + EXPECT( _.p1() != _.pv2 ); + EXPECT_NOT( _.p1() != _.pv1 ); +} + +CASE( "not_null<>: Allows to compare less than a raw pointer of the same type" ) +{ + NotNull _; + + EXPECT_NOT( _.p1() < _.pv1 ); + EXPECT( ( _.p1() < _.pv2 ) == ( _.pv1 < _.pv2 ) ); + EXPECT( ( _.p2() < _.pv1 ) == ( _.pv2 < _.pv1 ) ); +} + +CASE( "not_null<>: Allows to compare less than or equal to a raw pointer of the same type" ) +{ + NotNull _; + + EXPECT( ( _.p1() <= _.pv1 ) ); + EXPECT( ( _.p1() <= _.pv2 ) == ( _.pv1 <= _.pv2 ) ); + EXPECT( ( _.p2() <= _.pv1 ) == ( _.pv2 <= _.pv1 ) ); +} + +CASE( "not_null<>: Allows to compare greater than a raw pointer of the same type" ) +{ + NotNull _; + + EXPECT_NOT( _.p1() > _.pv1 ); + EXPECT( ( _.p1() > _.pv2 ) == ( _.pv1 > _.pv2 ) ); + EXPECT( ( _.p2() > _.pv1 ) == ( _.pv2 > _.pv1 ) ); +} + +CASE( "not_null<>: Allows to compare greater than or equal to a raw pointer of the same type" ) +{ + NotNull _; + + EXPECT( _.p1() >= _.pv1 ); + EXPECT( ( _.p1() >= _.pv2 ) == ( _.pv1 >= _.pv2 ) ); + EXPECT( ( _.p2() >= _.pv1 ) == ( _.pv2 >= _.pv1 ) ); +} + +#if gsl_STDLIB_CPP20_OR_GREATER +CASE( "not_null<>: Allows to 3-way compare with a raw pointer of the same type" ) +{ + NotNull _; + + EXPECT( ( _.p1() <=> _.pv1 == 0 ) ); + EXPECT( ( ( _.p1() <=> _.pv2 ) == ( _.pv1 <=> _.pv2 ) ) ); + EXPECT( ( ( _.p2() <=> _.pv1 ) == ( _.pv2 <=> _.pv1 ) ) ); +} +#endif // gsl_STDLIB_CPP20_OR_GREATER + +// user-defined types to check element_type deduction + +template<class T> +struct NormalPtr +{ + typedef T element_type; + T* ptr; + T& operator*() { return *ptr; } + NormalPtr(T* ptr) : ptr(ptr) {} +}; + +template<class T> +struct ETLessNormalPtr +{ + // no element_type typedef + T* ptr; + T& operator*() { return *ptr; } + ETLessNormalPtr(T* ptr) : ptr(ptr) {} +}; + +template<class T> +struct WeirdPtr // element_type and *p's type differ +{ + typedef T element_type; + T* ptr; + double operator*() { return *ptr; } + WeirdPtr(T* ptr) : ptr(ptr) {} +}; + +template<class T> +struct ETLessWeirdPtr // // element_type and type T differ +{ + // no element_type typedef + T* ptr; + double operator*() { return *ptr; } + ETLessWeirdPtr(T* ptr) : ptr(ptr) {} +}; + +#if gsl_HAVE( TYPE_TRAITS ) +using std::is_same; +#else +template<class T, class U> +struct is_same { enum dummy { value = false }; }; + +template<class T> +struct is_same<T, T> { enum dummy { value = true }; }; +#endif + +CASE( "not_null<>: Able to deduce element_type of raw pointers" ) +{ + EXPECT(( is_same< gsl_lite::not_null< int* >::element_type, int >::value )); + EXPECT(( is_same< gsl_lite::not_null< const int* >::element_type, const int >::value )); +} + +CASE( "not_null<>: Able to deduce element_type of unique_ptr" ) +{ +#if gsl_HAVE( UNIQUE_PTR ) + EXPECT(( is_same< gsl_lite::not_null< std::unique_ptr< int > >::element_type, int >::value )); + EXPECT(( is_same< gsl_lite::not_null< std::unique_ptr< const int > >::element_type, const int >::value )); +#endif +} + +CASE( "not_null<>: Able to deduce element_type of shared_ptr" ) +{ +#if gsl_HAVE( SHARED_PTR ) + EXPECT(( is_same< gsl_lite::not_null< std::shared_ptr< int > >::element_type, int >::value )); + EXPECT(( is_same< gsl_lite::not_null< std::shared_ptr< const int > >::element_type, const int >::value )); +#endif +} + +CASE( "not_null<>: Able to deduce element_type of normal user-defined smart pointers" ) +{ + EXPECT(( is_same< gsl_lite::not_null< NormalPtr< int > >::element_type, int >::value )); + EXPECT(( is_same< gsl_lite::not_null< NormalPtr< const int > >::element_type, const int >::value )); +} + +CASE( "not_null<>: Able to correctly deduce element_type of user-defined smart pointers even if typedef and result of dereferencing differs" ) +{ + EXPECT(( is_same< gsl_lite::not_null< WeirdPtr< int > >::element_type, int >::value )); + EXPECT(( is_same< gsl_lite::not_null< WeirdPtr< const int > >::element_type, const int >::value )); +} + +CASE( "not_null<>: Able to deduce element_type of user-defined smart pointers even if they do not have an element_type typedef" ) +{ +#if gsl_CPP11_OR_GREATER + EXPECT(( is_same< gsl_lite::not_null< ETLessNormalPtr< int > >::element_type, int >::value )); + EXPECT(( is_same< gsl_lite::not_null< ETLessNormalPtr< const int > >::element_type, const int >::value )); +#endif +} + +CASE( "not_null<>: Able to deduce element_type of user-defined smart pointers even if they do not have an element_type typedef, and element_type differs from T" ) +{ +#if gsl_CPP11_OR_GREATER + EXPECT(( is_same< gsl_lite::not_null< ETLessWeirdPtr< int > >::element_type, double >::value )); + EXPECT(( is_same< gsl_lite::not_null< ETLessWeirdPtr< const int > >::element_type, double >::value )); +#endif +} + +CASE( "not_null<>: Can handle void*" ) +{ + int i = 42; + void * vp = &i; + + // Direct construction + gsl_lite::not_null< void * > nvp( vp ); + EXPECT( nvp == vp ); + + // Indirect construction + nvp = gsl_lite::make_not_null( vp ); + EXPECT( nvp == vp ); + + // Implicit conversion from `not_null<>` with typed pointer argument + gsl_lite::not_null< int * > nip( &i ); + EXPECT( nvp == nip ); + gsl_lite::not_null< void * > nvp2( nip ); + EXPECT( nvp2 == nip ); + + // Implicit conversion from typed pointer + EXPECT( nvp == &i ); + gsl_lite::not_null< void * > nvp3( &i ); + EXPECT( nvp3 == nip ); + + // Extract underlying value + void * vp2 = gsl_lite::as_nullable( nvp ); + EXPECT( vp2 == vp ); + + // Explicit conversion to typed pointer argument is not supported! + //gsl_lite::not_null< int * > nip2 = static_cast< gsl_lite::not_null< int * > >( nvp ); + //gsl_lite::not_null< int * > nip2 = gsl_lite::not_null< int * >( nvp ); + //int * ip = static_cast< int * >( nvp ); +} + +void int_const_deleter( void const * p ) +{ + int const * pi = static_cast< int const * >( p ); + delete pi; +} + +CASE( "not_null<>: Can handle unique_ptr<void, DeleterT>" ) +{ +#if gsl_CPP11_OR_GREATER + std::unique_ptr< void, void ( * )( void const * ) > vp( new int( 42 ), int_const_deleter ); + void * p = vp.get(); + ( void ) p; + + // Direct construction + gsl_lite::not_null< std::unique_ptr< void, void ( * )( void const * ) > > nvp( std::move( vp ) ); +# if gsl_CONFIG( TRANSPARENT_NOT_NULL ) + EXPECT( nvp.get() == p ); +# endif // gsl_CONFIG( TRANSPARENT_NOT_NULL ) + vp = std::move( nvp ); + + // Indirect construction + nvp = gsl_lite::make_not_null( std::move( vp ) ); +# if gsl_CONFIG( TRANSPARENT_NOT_NULL ) + EXPECT( nvp.get() == p ); +# endif // gsl_CONFIG( TRANSPARENT_NOT_NULL ) + + // Implicit conversion from `not_null<>` with typed pointer argument + std::unique_ptr< int, void ( * )( void const * ) > tp2( new int( 42 ), int_const_deleter ); + int * pi2 = tp2.get(); + ( void ) pi2; + gsl_lite::not_null< std::unique_ptr< int, void ( * )( void const * ) > > ntp2( std::move( tp2 ) ); +# if gsl_CONFIG( TRANSPARENT_NOT_NULL ) + EXPECT( ntp2.get() == pi2 ); +# endif // gsl_CONFIG( TRANSPARENT_NOT_NULL ) + gsl_lite::not_null< std::unique_ptr< void, void ( * )( void const * ) > > nvp2( std::move( ntp2 ) ); +# if gsl_CONFIG( TRANSPARENT_NOT_NULL ) + EXPECT( nvp2.get() == pi2 ); +# endif // gsl_CONFIG( TRANSPARENT_NOT_NULL ) + + // Implicit conversion from typed pointer + std::unique_ptr< int, void ( * )( void const * ) > tp3( new int( 42 ), int_const_deleter ); + int * pi3 = tp3.get(); + gsl_lite::not_null< std::unique_ptr< void, void ( * )( void const * ) > > nvp3( std::move( tp3 ) ); +# if gsl_CONFIG( TRANSPARENT_NOT_NULL ) + EXPECT( nvp3.get() == pi3 ); +# endif // gsl_CONFIG( TRANSPARENT_NOT_NULL ) + + // Extract underlying value + std::unique_ptr< void, void ( * )( void const * ) > vp3 = gsl_lite::as_nullable( std::move( nvp3 ) ); + EXPECT( vp3.get() == pi3 ); + + // Explicit conversion to typed pointer argument is not supported! +#endif +} + +CASE( "not_null<>: Can handle shared_ptr<void>" ) +{ +#if gsl_CPP11_OR_GREATER + std::shared_ptr< void > vp = std::make_shared<int>( 42 ); + void * p = vp.get(); + ( void ) p; + + // Direct construction + gsl_lite::not_null< std::shared_ptr< void > > nvp( vp ); +# if gsl_CONFIG( TRANSPARENT_NOT_NULL ) + EXPECT( nvp.get() == p ); +# endif // gsl_CONFIG( TRANSPARENT_NOT_NULL ) + vp = std::move( nvp ); + + // Indirect construction + nvp = gsl_lite::make_not_null( vp ); +# if gsl_CONFIG( TRANSPARENT_NOT_NULL ) + EXPECT( nvp.get() == p ); +# endif // gsl_CONFIG( TRANSPARENT_NOT_NULL ) + + // Implicit conversion from `not_null<>` with typed pointer argument + std::shared_ptr< int > tp2 = std::make_shared<int>( 42 ); + int * pi2 = tp2.get(); + gsl_lite::not_null< std::shared_ptr< int > > ntp2( tp2 ); +# if gsl_CONFIG( TRANSPARENT_NOT_NULL ) + EXPECT( ntp2.get() == pi2 ); +# endif // gsl_CONFIG( TRANSPARENT_NOT_NULL ) + gsl_lite::not_null< std::shared_ptr< void > > nvp2( ntp2 ); +# if gsl_CONFIG( TRANSPARENT_NOT_NULL ) + EXPECT( nvp2.get() == pi2 ); +# endif // gsl_CONFIG( TRANSPARENT_NOT_NULL ) + + // Implicit conversion from typed pointer + gsl_lite::not_null< std::shared_ptr< void > > nvp2b( tp2 ); +# if gsl_CONFIG( TRANSPARENT_NOT_NULL ) + EXPECT( nvp2b.get() == pi2 ); +# endif // gsl_CONFIG( TRANSPARENT_NOT_NULL ) + + // Extract underlying value + std::shared_ptr< void > vp2 = gsl_lite::as_nullable( nvp2 ); + EXPECT( vp2.get() == pi2 ); + + // Explicit conversion to typed pointer argument is not supported! +#endif +} + +#if gsl_HAVE( HASH ) + +CASE( "not_null<>: Hashes match the hashes of the wrapped pointer" ) +{ + int i = 42; + not_null< const int* > raw_pointer = make_not_null( &i ); + EXPECT( std::hash< not_null< const int* > >()(raw_pointer) == std::hash< const int* >()( as_nullable( raw_pointer ) ) ); +# if gsl_HAVE( UNIQUE_PTR ) + not_null< std::unique_ptr< int > > unique_pointer = make_not_null( my_make_unique< int >(43) ); + EXPECT( std::hash< not_null< std::unique_ptr< int > > >()(unique_pointer) == std::hash< std::unique_ptr< int > >()( as_nullable( unique_pointer) ) ); +# endif // gsl_HAVE( UNIQUE_PTR ) +# if gsl_HAVE( SHARED_PTR ) + not_null< std::shared_ptr< int > > shared_pointer = make_not_null( std::make_shared< int >(43) ); + EXPECT( std::hash< not_null< std::shared_ptr< int > > >()(shared_pointer) == std::hash< std::shared_ptr< int > >()( as_nullable( shared_pointer) ) ); +# endif // gsl_HAVE( SHARED_PTR ) +} + +CASE( "not_null<>: Hash functor disabled for non-hashable pointers and enabled for hashable pointers" ) +{ + EXPECT(( std::is_default_constructible< std::hash< not_null< int* > > >::value )); + EXPECT(( std::is_default_constructible< std::hash< not_null< std::unique_ptr< int > > > >::value )); + EXPECT(( std::is_default_constructible< std::hash< not_null< std::shared_ptr< int > > > >::value )); +# if gsl_STDLIB_CPP14_OR_GREATER && ! gsl_BETWEEN( gsl_COMPILER_MSVC_VERSION, 1, 141 ) && ! gsl_BETWEEN( gsl_COMPILER_APPLECLANG_VERSION, 1, 900 ) + // std::hash< NormalPtr< int > > isn't guaranteed to exist at all in C++11 + EXPECT_NOT( ( std::is_default_constructible< std::hash< not_null< NormalPtr< int > > > >::value ) ); +# endif +} + +#endif // gsl_HAVE( HASH ) + +#if gsl_STDLIB_CPP11_140 && ( gsl_CPP14_OR_GREATER || ! gsl_COMPILER_NVCC_VERSION ) + +int inspector( int const& p ) +{ + return p; +} +int mutator( int & p ) +{ + p = 42; + return p; +} +int extractor( std::unique_ptr< int > value ) +{ + return *value; +} + +CASE( "not_null<>: Supports function pointer type for construction, assignment, and invocation" ) +{ +# if ! gsl_BETWEEN( gsl_COMPILER_CLANG_VERSION, 1, 400 ) && ! gsl_BETWEEN( gsl_COMPILER_APPLECLANG_VERSION, 1, 1001 ) + not_null< int (*)( int const& ) > insp = inspector; + int i = 41; + EXPECT( insp( i ) == 41 ); + + not_null< int (*)( int & ) > mut = mutator; + mut( i ); + EXPECT( i == 42 ); + + not_null< int (*)( std::unique_ptr< int > ) > xtr = extractor; + EXPECT( xtr( my_make_unique< int >( 1 ) ) == 1 ); +# endif // ! gsl_BETWEEN( gsl_COMPILER_CLANG_VERSION, 1, 400 ) && ! gsl_BETWEEN( gsl_COMPILER_APPLECLANG_VERSION, 1, 1001 ) +} + +CASE( "not_null<>: Supports std::function<> for construction, assignment, and invocation" ) +{ + not_null< std::function< int( int ) > > insp = make_not_null( std::function< int( int ) >( inspector ) ); + int i = 41; + EXPECT( insp( i ) == 41 ); + auto insp2 = std::move( insp ); + EXPECT( insp2( i ) == 41 ); + if ( ! gsl_lite::is_valid( insp ) ) // a moved-from `std::function<>` object is in a valid but unspecified state, and may thus still be holding the old value + { + EXPECT_THROWS( insp( i ) ); + } + + not_null< std::function< int( int & ) > > mut = make_not_null( std::function< int( int & ) >( mutator ) ); + mut( i ); + EXPECT( i == 42 ); + mut = std::move( insp2 ); + i = 41; + mut( i ); + EXPECT( i == 41 ); + + not_null< std::function< int( std::unique_ptr< int > ) > > xtr = make_not_null( std::function< int( std::unique_ptr< int > ) >( extractor ) ); + EXPECT( xtr( my_make_unique< int >( 1 ) ) == 1 ); +} + +CASE( "not_null<>: Supports converting to std::function<> from function reference" ) +{ +# if ! gsl_BETWEEN( gsl_COMPILER_CLANG_VERSION, 1, 400 ) && ! gsl_BETWEEN( gsl_COMPILER_APPLECLANG_VERSION, 1, 1001 ) + not_null< std::function< int( int ) > > insp = inspector; + int i = 41; + EXPECT( insp( i ) == 41 ); + auto insp2 = std::move( insp ); + EXPECT( insp2( i ) == 41 ); + if ( ! gsl_lite::is_valid( insp ) ) // a moved-from `std::function<>` object is in a valid but unspecified state, and may thus still be holding the old value + { + EXPECT_THROWS( insp( i ) ); + } + + not_null< std::function< int( int & ) > > mut = mutator; + mut( i ); + EXPECT( i == 42 ); + mut = inspector; + i = 41; + mut( i ); + EXPECT( i == 41 ); +# endif // ! gsl_BETWEEN( gsl_COMPILER_CLANG_VERSION, 1, 400 ) && ! gsl_BETWEEN( gsl_COMPILER_APPLECLANG_VERSION, 1, 1001 ) +} + +struct Mutator +{ + template < typename T > + T + operator ()( T& arg ) + { + arg = { }; + return arg; + } +}; +struct Inspector +{ + template < typename T > + T + operator ()( T arg ) + { + return arg; + } +}; + +CASE( "not_null<>: Supports constructing and assigning std::function<> from non-nullable function object" ) +{ +# if ! gsl_BETWEEN( gsl_COMPILER_CLANG_VERSION, 1, 400 ) && ! gsl_BETWEEN( gsl_COMPILER_APPLECLANG_VERSION, 1, 1001 ) + not_null< std::function< int( int& ) > > insp = Inspector{ }; + int i = 41; + EXPECT( insp( i ) == 41 ); + + not_null< std::function< int( int & ) > > mut = Mutator{ }; + mut( i ); + EXPECT( i == 0 ); + mut = Inspector{ }; + i = 41; + mut( i ); + EXPECT( i == 41 ); +# endif // ! gsl_BETWEEN( gsl_COMPILER_CLANG_VERSION, 1, 400 ) && ! gsl_BETWEEN( gsl_COMPILER_APPLECLANG_VERSION, 1, 1001 ) +} +#endif // gsl_STDLIB_CPP11_140 && ( gsl_CPP14_OR_GREATER || ! gsl_COMPILER_NVCC_VERSION ) + +CASE( "not_null<>: Invocability is correctly reported by type traits" ) +{ +#if gsl_STDLIB_CPP17_OR_GREATER + + // No invocability for raw pointers. + static_assert( !std::is_invocable< not_null< int* > >::value ); + static_assert( !std::is_invocable< not_null< int* >, int >::value ); + + // No invocability for `unique_ptr<>`. + static_assert( !std::is_invocable< not_null< unique_ptr< int > > >::value ); + static_assert( !std::is_invocable< not_null< unique_ptr< int > >, int >::value ); + + // Invocability for function pointers with suitable argument list. + static_assert( std::is_invocable< not_null< int (*)( ) > >::value ); + static_assert( std::is_invocable< not_null< int (*)( int const& ) >, int & >::value ); + static_assert( std::is_invocable< not_null< int (*)( int & ) >, int & >::value ); + static_assert( !std::is_invocable< not_null< int (*)( int & ) >, int >::value ); + + // Invocability for `std::function<>` with suitable argument list. + static_assert( std::is_invocable< not_null< std::function< int( ) > > >::value ); + static_assert( std::is_invocable< not_null< std::function< int( int const& ) > >, int & >::value ); + static_assert( std::is_invocable< not_null< std::function< int( int & ) > >, int & >::value ); + static_assert( !std::is_invocable< not_null< std::function< int( int & ) > >, int >::value ); + + // Correct return type is inferred for function pointers. + static_assert( std::is_invocable_r< void, not_null< int & (*)( int const& ) >, int >::value ); + static_assert( std::is_invocable_r< int &, not_null< int & (*)( int const& ) >, int >::value ); + static_assert( !std::is_invocable_r< int &, not_null< int (*)( int const& ) >, int >::value ); + + // Correct return type is inferred for `std::function<>`. + static_assert( std::is_invocable_r< void, not_null< std::function<int &( int const& ) > >, int >::value ); + static_assert( std::is_invocable_r< int &, not_null< std::function<int &( int const& ) > >, int >::value ); + static_assert( !std::is_invocable_r< int &, not_null< std::function<int ( int const& ) > >, int >::value ); + +#endif // gsl_STDLIB_CPP20_OR_GREATER +} + + +// end of file diff --git a/thirdparty/gsl-lite/test/owner.t.cpp b/thirdparty/gsl-lite/test/owner.t.cpp new file mode 100644 index 000000000..d576a706b --- /dev/null +++ b/thirdparty/gsl-lite/test/owner.t.cpp @@ -0,0 +1,67 @@ +// +// gsl-lite is based on GSL: Guidelines Support Library. +// For more information see https://github.com/gsl-lite/gsl-lite +// +// Copyright (c) 2015-2019 Martin Moene +// Copyright (c) 2019-2021 Moritz Beutel +// Copyright (c) 2015-2018 Microsoft Corporation. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "gsl-lite.t.hpp" + +using namespace gsl_lite; + +CASE( "owner<>: Disallows construction from a non-pointer type (define gsl_CONFIG_CONFIRMS_COMPILATION_ERRORS)" ) +{ +#if gsl_CONFIG( CONFIRMS_COMPILATION_ERRORS ) +# if gsl_HAVE( TYPE_TRAITS ) + owner<int> p = gsl_nullptr; +# else + EXPECT( !!"owner<> alias template restricted to pointer type is not available." ); +# endif +#endif +} + +CASE( "owner<>: Allows its use as the (pointer) type it stands for" ) +{ +#if gsl_HAVE( OWNER_TEMPLATE ) + struct F { static void incr( int * i ) { *i += 1; } }; + + owner<int*> p = new int( 120 ); + + EXPECT( (p != NULL) ); + EXPECT( p != nullptr_void() ); +# if gsl_HAVE( NULLPTR ) + EXPECT( p != nullptr ); +# endif + EXPECT( *p == 120 ); + + F::incr( p ); + + EXPECT( *p == 121 ); + delete p; + +#if gsl_FEATURE( GSL_LITE_NAMESPACE ) + // Also try to consume `owner<>` from the `gsl_lite` namespace + gsl_lite::owner<int*> p2 = new int( 120 ); + EXPECT( ( p2 != NULL ) ); + EXPECT( *p2 == 120 ); + F::incr( p2 ); + EXPECT( *p2 == 121 ); + delete p2; +#endif +#else + EXPECT( !!"owner<> alias template is not available." ); +#endif +} + +// end of file diff --git a/thirdparty/gsl-lite/test/span.t.cpp b/thirdparty/gsl-lite/test/span.t.cpp new file mode 100644 index 000000000..86dd05607 --- /dev/null +++ b/thirdparty/gsl-lite/test/span.t.cpp @@ -0,0 +1,2199 @@ +// +// gsl-lite is based on GSL: Guidelines Support Library. +// For more information see https://github.com/gsl-lite/gsl-lite +// +// Copyright (c) 2015-2019 Martin Moene +// Copyright (c) 2019-2021 Moritz Beutel +// Copyright (c) 2015-2018 Microsoft Corporation. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "gsl-lite.t.hpp" + +using namespace gsl_lite; + +typedef span<int>::size_type size_type; +typedef std::ptrdiff_t difference_type; + + +static std::vector<int> vector_iota( int n ) +{ + std::vector<int> result; + + for ( int i = 0; i < n; ++i ) + result.push_back( i ); + + return result; +} + +CASE( "span<>: Disallows construction from a temporary value (C++11) (define gsl_CONFIG_CONFIRMS_COMPILATION_ERRORS)" ) +{ +#if gsl_CONFIG( CONFIRMS_COMPILATION_ERRORS ) +# if gsl_HAVE( IS_DELETE ) + span<int> v = 42; +# endif +#endif +} + +CASE( "span<>: Disallows construction from a C-array of incompatible type (define gsl_CONFIG_CONFIRMS_COMPILATION_ERRORS)" ) +{ +#if gsl_CONFIG( CONFIRMS_COMPILATION_ERRORS ) + short arr[] = { 1, 2, 3, }; + span<int> v = arr; +#endif +} + +CASE( "span<>: Disallows construction from a std::array of incompatible type (C++11) (define gsl_CONFIG_CONFIRMS_COMPILATION_ERRORS)" ) +{ +#if gsl_CONFIG( CONFIRMS_COMPILATION_ERRORS ) +# if gsl_HAVE( ARRAY ) + std::array<long,3> arr = {{ 1L, 2L, 3L, }}; + span<int> v( arr); +# endif +#endif +} + +CASE( "span<>: Terminates construction from pointer with a mismatching size" ) +{ + struct F { static void blow() { int a[2]; span<int, 3> v( a, 2 ); (void) v.size(); } }; + struct G { static void blow() { int a[2]; span<int, 3> v( a, a + 2 ); (void) v.size(); } }; + + EXPECT_THROWS( F::blow() ); + EXPECT_THROWS( G::blow() ); +} + +CASE( "span<>: Terminates construction from iterator with a mismatching size" ) +{ + struct F { static void blow() { int a[2]; span<int> u(a); span<int, 3> v( u.begin(), 2 ); (void) v.size(); } }; + struct G { static void blow() { int a[2]; span<int> u(a); span<int, 3> v( u.begin(), u.begin() + 2 ); (void) v.size(); } }; + struct H { static void blow() { int a[2]; span<int, 2> u(a); span<int, 3> v( u.begin(), 2 ); (void) v.size(); } }; + struct I { static void blow() { int a[2]; span<int, 2> u(a); span<int, 3> v( u.begin(), u.begin() + 2 ); (void) v.size(); } }; + + EXPECT_THROWS( F::blow() ); + EXPECT_THROWS( G::blow() ); + EXPECT_THROWS( H::blow() ); + EXPECT_THROWS( I::blow() ); +} + +CASE( "span<>: Terminates construction from a nullptr and a non-zero size (C++11)" ) +{ +#if gsl_HAVE( NULLPTR ) + struct F { static void blow() { span<int> v( nullptr, 42 ); (void) v.size(); } }; + struct G { static void blow() { span<int, 42> v( nullptr, 42 ); (void) v.size(); } }; + + EXPECT_THROWS( F::blow() ); + EXPECT_THROWS( G::blow() ); +#else + EXPECT( !!"nullptr is not available (no C++11)" ); +#endif +} + +CASE( "span<>: Terminates construction from two pointers in the wrong order" ) +{ + struct F { static void blow() { int a[2]; span<int> v( &a[2], &a[0] ); (void) v.size(); } }; + struct G { static void blow() { int a[2]; span<int, 2> v( &a[2], &a[0] ); (void) v.size(); } }; + + EXPECT_THROWS( F::blow() ); + EXPECT_THROWS( G::blow() ); +} + +CASE( "span<>: Terminates construction from two iterators in the wrong order" ) +{ + struct F { static void blow() { int a[2]; span<int> u( a ); span<int> v( u.begin() + 2, u.begin() ); (void) v.size(); } }; + struct G { static void blow() { int a[2]; span<int> u( a ); span<int, 2> v( u.begin() + 2, u.begin() ); (void) v.size(); } }; + + EXPECT_THROWS( F::blow() ); + EXPECT_THROWS( G::blow() ); +} + +CASE( "span<>: Terminates construction from a null pointer and a non-zero size" ) +{ + struct F { static void blow() { int * p = gsl_nullptr; span<int> v( p, 42 ); (void) v.size(); } }; + struct G { static void blow() { int * p = gsl_nullptr; span<int, 42> v( p, 42 ); (void) v.size(); } }; + + EXPECT_THROWS( F::blow() ); + EXPECT_THROWS( G::blow() ); +} + +CASE( "span<>: Terminates construction from a default-constructed iterator and a non-zero size" ) +{ + struct F { static void blow() { span<int>::iterator it; span<int> v( it, 42 ); (void) v.size(); } }; + struct G { static void blow() { span<int>::iterator it; span<int, 42> v( it, 42 ); (void) v.size(); } }; + + EXPECT_THROWS( F::blow() ); + EXPECT_THROWS( G::blow() ); +} + +CASE( "span<>: Terminates creation of a sub span of the first n elements for n exceeding the span" ) +{ + struct F { + static void blow() + { + int arr[] = { 1, 2, 3, }; + span<int> v( arr ); + + (void) v.first( 4 ); + }}; + struct G { + static void blow() + { + int arr[] = { 1, 2, 3, }; + span<int, 3> v( arr ); + + (void) v.first( 4 ); + }}; + + EXPECT_THROWS( F::blow() ); + EXPECT_THROWS( G::blow() ); +} + +CASE( "span<>: Terminates creation of a sub span of the last n elements for n exceeding the span" ) +{ + struct F { + static void blow() + { + int arr[] = { 1, 2, 3, }; + span<int> v( arr ); + + (void) v.last( 4 ); + }}; + struct G { + static void blow() + { + int arr[] = { 1, 2, 3, }; + span<int, 3> v( arr ); + + (void) v.last( 4 ); + }}; + + EXPECT_THROWS( F::blow() ); + EXPECT_THROWS( G::blow() ); +} + +CASE( "span<>: Terminates creation of a sub span outside the span" ) +{ + struct F { + static void blow_offset() + { + int arr[] = { 1, 2, 3, }; + span<int> v( arr ); + + (void) v.subspan( 4 ); + } + static void blow_count() + { + int arr[] = { 1, 2, 3, }; + span<int> v( arr ); + + (void) v.subspan( 1, 3 ); + }}; + struct G { + static void blow_offset() + { + int arr[] = { 1, 2, 3, }; + span<int, 3> v( arr ); + + (void) v.subspan( 4 ); + } + static void blow_count() + { + int arr[] = { 1, 2, 3, }; + span<int, 3> v( arr ); + + (void) v.subspan( 1, 3 ); + }}; + + EXPECT_THROWS( F::blow_offset() ); + EXPECT_THROWS( F::blow_count() ); + EXPECT_THROWS( G::blow_offset() ); + EXPECT_THROWS( G::blow_count() ); +} + +CASE( "span<>: Terminates access outside the span" ) +{ + struct F { + static void blow_ix(size_t i) { int arr[] = { 1, 2, 3, }; span<int> v( arr ); (void) v[i]; } + }; + struct G { + static void blow_ix(size_t i) { int arr[] = { 1, 2, 3, }; span<int, 3> v( arr ); (void) v[i]; } + }; + + EXPECT_NO_THROW( F::blow_ix(2) ); + EXPECT_THROWS( F::blow_ix(3) ); + EXPECT_NO_THROW( G::blow_ix(2) ); + EXPECT_THROWS( G::blow_ix(3) ); +} + +CASE( "span<>: Terminates access with front() and back() on empty span" ) +{ + EXPECT_THROWS( (void) span<int>().front() ); + EXPECT_THROWS( (void) span<int>().back() ); + EXPECT_THROWS(( (void) span<int, 0>().front() )); + EXPECT_THROWS(( (void) span<int, 0>().back() )); +} + +CASE( "span<>: Allows to default-construct" ) +{ + span<int> v; + span<int, 0> w; + + EXPECT( v.size() == size_type( 0 ) ); + EXPECT( w.size() == size_type( 0 ) ); +} + +CASE( "span<>: Allows to construct from a nullptr and a zero size (C++11)" ) +{ +#if gsl_HAVE( NULLPTR ) + span< int> v ( nullptr, size_type( 0 ) ); + span<const int> cv( nullptr, size_type( 0 ) ); + span< int, 0> w ( nullptr, size_type( 0 ) ); + span<const int, 0> cw( nullptr, size_type( 0 ) ); + + EXPECT( v.size() == size_type( 0 ) ); + EXPECT( cv.size() == size_type( 0 ) ); + EXPECT( w.size() == size_type( 0 ) ); + EXPECT( cw.size() == size_type( 0 ) ); +#else + EXPECT( !!"nullptr is not available (no C++11)" ); +#endif +} + +CASE( "span<>: Allows to construct from a default-constructed iterator and a zero size" ) +{ + span<int>::iterator it; + span< int> v ( it, size_type( 0 ) ); + span<const int> cv( it, size_type( 0 ) ); + span< int, 0> w ( it, size_type( 0 ) ); + span<const int, 0> cw( it, size_type( 0 ) ); + + EXPECT( v.size() == size_type( 0 ) ); + EXPECT( cv.size() == size_type( 0 ) ); + EXPECT( w.size() == size_type( 0 ) ); + EXPECT( cw.size() == size_type( 0 ) ); +} + +CASE( "span<>: Allows to construct from two pointers" ) +{ + int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, }; + + span< int> v ( arr, arr + gsl_DIMENSION_OF( arr ) ); + span<const int> cv( arr, arr + gsl_DIMENSION_OF( arr ) ); + span< int, 9> w ( arr, arr + gsl_DIMENSION_OF( arr ) ); + span<const int, 9> cw( arr, arr + gsl_DIMENSION_OF( arr ) ); + + EXPECT( std::equal( v.begin(), v.end(), arr ) ); + EXPECT( std::equal( cv.begin(), cv.end(), arr ) ); + EXPECT( std::equal( w.begin(), w.end(), arr ) ); + EXPECT( std::equal( cw.begin(), cw.end(), arr ) ); +} + +CASE( "span<>: Allows to construct from two iterators" ) +{ + int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, }; + + span<int> u( arr ); + span< int> v ( u.begin(), u.begin() + u.ssize() ); + span<const int> cv( u.begin(), u.begin() + u.ssize() ); + span< int, 9> w ( u.begin(), u.begin() + u.ssize() ); + span<const int, 9> cw( u.begin(), u.begin() + u.ssize() ); + + EXPECT( std::equal( v.begin(), v.end(), arr ) ); + EXPECT( std::equal( cv.begin(), cv.end(), arr ) ); + EXPECT( std::equal( w.begin(), w.end(), arr ) ); + EXPECT( std::equal( cw.begin(), cw.end(), arr ) ); +} + +CASE( "span<>: Allows to construct from two pointers to const" ) +{ + const int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, }; + + span<const int> cv( arr, arr + gsl_DIMENSION_OF( arr ) ); + span<const int, 9> cw( arr, arr + gsl_DIMENSION_OF( arr ) ); + + EXPECT( std::equal( cv.begin(), cv.end(), arr ) ); + EXPECT( std::equal( cw.begin(), cw.end(), arr ) ); +} + +CASE( "span<>: Allows to construct from a non-null pointer and a size" ) +{ + int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, }; + + span< int> v ( arr, gsl_DIMENSION_OF( arr ) ); + span<const int> cv( arr, gsl_DIMENSION_OF( arr ) ); + span< int, 9> w ( arr, gsl_DIMENSION_OF( arr ) ); + span<const int, 9> cw( arr, gsl_DIMENSION_OF( arr ) ); + + EXPECT( std::equal( v.begin(), v.end(), arr ) ); + EXPECT( std::equal( cv.begin(), cv.end(), arr ) ); + EXPECT( std::equal( w.begin(), w.end(), arr ) ); + EXPECT( std::equal( cw.begin(), cw.end(), arr ) ); +} + +CASE( "span<>: Allows to construct from an iterator and a size" ) +{ + int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, }; + + span<int> u( arr ); + span< int> v ( u.begin(), u.size() ); + span<const int> cv( u.begin(), u.size() ); + span< int, 9> w ( u.begin(), u.size() ); + span<const int, 9> cw( u.begin(), u.size() ); + + EXPECT( std::equal( v.begin(), v.end(), arr ) ); + EXPECT( std::equal( cv.begin(), cv.end(), arr ) ); + EXPECT( std::equal( w.begin(), w.end(), arr ) ); + EXPECT( std::equal( cw.begin(), cw.end(), arr ) ); +} + +CASE( "span<>: Allows to construct from a non-null pointer to const and a size" ) +{ + const int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, }; + + span<const int> cv( arr, gsl_DIMENSION_OF( arr ) ); + span<const int, 9> cw( arr, gsl_DIMENSION_OF( arr ) ); + + EXPECT( std::equal( cv.begin(), cv.end(), arr ) ); + EXPECT( std::equal( cw.begin(), cw.end(), arr ) ); +} + +CASE( "span<>: Allows to construct from a const iterator and a size" ) +{ + const int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, }; + + span<const int> u( arr ); + span<const int> cv( u.begin(), u.size() ); + span<const int, 9> cw( u.begin(), u.size() ); + + EXPECT( std::equal( cv.begin(), cv.end(), arr ) ); + EXPECT( std::equal( cw.begin(), cw.end(), arr ) ); +} + +CASE( "span<>: Allows to construct from a temporary pointer and a size" ) +{ + int x = 42; + + span< int> v ( &x, 1 ); + span<const int> cv( &x, 1 ); + span< int, 1> w ( &x, 1 ); + span<const int, 1> cw( &x, 1 ); + + EXPECT( std::equal( v.begin(), v.end(), &x ) ); + EXPECT( std::equal( cv.begin(), cv.end(), &x ) ); + EXPECT( std::equal( w.begin(), w.end(), &x ) ); + EXPECT( std::equal( cw.begin(), cw.end(), &x ) ); +} + +CASE( "span<>: Allows to construct from a temporary pointer to const and a size" ) +{ + const int x = 42; + + span<const int> cv( &x, 1 ); + span<const int, 1> cw( &x, 1 ); + + EXPECT( std::equal( cv.begin(), cv.end(), &x ) ); + EXPECT( std::equal( cw.begin(), cw.end(), &x ) ); +} + +CASE( "span<>: Allows to construct from any pointer and a zero size" ) +{ + struct F { + static void null() { + int * p = gsl_nullptr; span<int> v( p, size_type( 0 ) ); + } + static void nonnull() { + int i = 7; int * p = &i; span<int> v( p, size_type( 0 ) ); + } + }; + + EXPECT_NO_THROW( F::null() ); + EXPECT_NO_THROW( F::nonnull() ); +} + +CASE( "span<>: Allows to construct from any iterator and a zero size" ) +{ + struct F { + static void null() { + span<int>::iterator it; span<int> v( it, size_type( 0 ) ); + } + static void nonnull() { + int a[2]; span<int> u( a ); span<int> v( u.begin(), size_type( 0 ) ); + } + }; + + EXPECT_NO_THROW( F::null() ); + EXPECT_NO_THROW( F::nonnull() ); +} + +CASE( "span<>: Allows to construct from a C-array" ) +{ + int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, }; + + span< int> v ( arr ); + span<const int> cv( arr ); + span< int, 9> w ( arr ); + span<const int, 9> cw( arr ); + + EXPECT( std::equal( v.begin(), v.end(), arr ) ); + EXPECT( std::equal( cv.begin(), cv.end(), arr ) ); + EXPECT( std::equal( w.begin(), w.end(), arr ) ); + EXPECT( std::equal( cw.begin(), cw.end(), arr ) ); +} + +CASE( "span<>: Allows to construct from a const C-array" ) +{ + const int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, }; + + span<const int> cv( arr ); + span<const int, 9> cw( arr ); + + EXPECT( std::equal( cv.begin(), cv.end(), arr ) ); + EXPECT( std::equal( cw.begin(), cw.end(), arr ) ); +} + +CASE( "span<>: Allows to construct from a C-array with size via decay to pointer (potentially dangerous)" ) +{ + int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, }; + + { + span< int> v( arr, gsl_DIMENSION_OF(arr) ); + span<const int> w( arr, gsl_DIMENSION_OF(arr) ); + + EXPECT( std::equal( v.begin(), v.end(), arr ) ); + EXPECT( std::equal( w.begin(), w.end(), arr ) ); + } + +#if gsl_CPP14_OR_GREATER + { + span< int> v( arr, 3 ); + span<const int> w( arr, 3 ); + + EXPECT( std::equal( v.begin(), v.end(), arr, arr + 3 ) ); + EXPECT( std::equal( w.begin(), w.end(), arr, arr + 3 ) ); + } +#endif +} + +CASE( "span<>: Allows to construct from a const C-array with size via decay to pointer (potentially dangerous)" ) +{ + const int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, }; + + { + span<const int> v( arr, gsl_DIMENSION_OF(arr) ); + + EXPECT( std::equal( v.begin(), v.end(), arr ) ); + } + +#if gsl_CPP14_OR_GREATER + { + span<const int> w( arr, 3 ); + + EXPECT( std::equal( w.begin(), w.end(), arr, arr + 3 ) ); + } +#endif +} + +CASE( "span<>: Allows to construct from a std::initializer_list<> (C++11)" ) +{ +#if gsl_HAVE( INITIALIZER_LIST ) && ( gsl_HAVE( CONSTRAINED_SPAN_CONTAINER_CTOR ) || gsl_HAVE( UNCONSTRAINED_SPAN_CONTAINER_CTOR ) ) + auto il = { 1, 2, 3, 4, 5, }; + + span<int const> v( il ); + + EXPECT( std::equal( v.begin(), v.end(), il.begin() ) ); +#else + EXPECT( !!"std::initializer_list<> is not available (no C++11)" ); +#endif +} + +CASE( "span<>: Allows to construct from a std::array<> (C++11)" ) +{ +# if gsl_HAVE( ARRAY ) + std::array<int,9> arr = {{ 1, 2, 3, 4, 5, 6, 7, 8, 9, }}; + + span<int> v( arr ); + span<int, 9> w( arr ); + + EXPECT( std::equal( v.begin(), v.end(), arr.begin() ) ); + EXPECT( std::equal( w.begin(), w.end(), arr.begin() ) ); + + span<const int> cv( arr ); + span<const int, 9> cw( arr ); + + EXPECT( std::equal( cv.begin(), cv.end(), arr.begin() ) ); + EXPECT( std::equal( cw.begin(), cw.end(), arr.begin() ) ); + +#else + EXPECT( !!"std::array<> is not available (no C++11)" ); +#endif +} + +gsl_constexpr14 int use_span_with_array( int const (&array)[3], span<int const> sp ) +{ + gsl_Assert( sp.size() == 3 ); + gsl_Assert( sp.front() == 0 ); + gsl_Assert( sp[1] == array[1] ); + gsl_Assert( sp.back() == 2 ); + gsl_Assert( sp.first( 0 ).size() == 0 ); + gsl_Assert( sp.last( 1 ).size() == 1 ); + gsl_Assert( sp.subspan( 1, 2 ).size() == 2 ); + gsl_Assert( ! sp.empty() ); + + int array2[3] = { 0, 0, 0 }; + span<int> sp2 = span<int>( array2 ); + sp = sp2; +#if gsl_CPP17_OR_GREATER + array2[0] = 1; + gsl_Assert( sp2[0] == 1 ); +#endif + sp2[1] = 2; + gsl_Assert( array2[1] == 2 ); + return 0; +} + +gsl_constexpr14 int use_fixed_span_with_array( int const (&array)[3], span<int const, 3> sp ) +{ + gsl_Assert( sp.size() == 3 ); + gsl_Assert( sp.front() == 0 ); + gsl_Assert( sp[1] == array[1] ); + gsl_Assert( sp.back() == 2 ); + gsl_Assert( sp.first( 0 ).size() == 0 ); + gsl_Assert( sp.last( 1 ).size() == 1 ); + gsl_Assert( sp.subspan( 1, 2 ).size() == 2 ); + gsl_Assert( ! sp.empty() ); + + int array2[3] = { 0, 0, 0 }; + span<int, 3> sp2 = span<int, 3>( array2 ); + sp = sp2; +#if gsl_CPP17_OR_GREATER + array2[0] = 1; + gsl_Assert( sp2[0] == 1 ); +#endif + sp2[1] = 2; + gsl_Assert( array2[1] == 2 ); + return 0; +} + +CASE("span<>: Allows constexpr use (C++14)") +{ +#if gsl_HAVE( CONSTEXPR_14 ) && ! gsl_BETWEEN( gsl_COMPILER_GNUC_VERSION, 1, 700 ) + constexpr int array[3] = { 0, 1, 2 }; +# if gsl_FEATURE_TO_STD( MAKE_SPAN ) + constexpr int r1 = use_span_with_array( array, make_span( array ) ); + constexpr int r2 = use_span_with_array( array, make_span( array, array + 3 ) ); + constexpr int r3 = use_span_with_array( array, make_span( array, 3 ) ); + constexpr int s1 = use_fixed_span_with_array( array, make_span( array ) ); +# endif + constexpr int r4 = use_span_with_array( array, span<int const>( array ) ); + constexpr int r5 = use_span_with_array( array, span<int const>( array, array + 3 ) ); + constexpr int r6 = use_span_with_array( array, span<int const>( array, 3 ) ); + constexpr int s2 = use_fixed_span_with_array( array, span<int const, 3>( array ) ); + EXPECT( (r1 | r2 | r3 | r4 | r5 | r6) == 0 ); + EXPECT( (s1 | s2) == 0 ); +# if gsl_HAVE( DEDUCTION_GUIDES ) + constexpr int r7 = use_span_with_array( array, span( array ) ); + constexpr int r8 = use_span_with_array( array, span( array, array + 3 ) ); + constexpr int r9 = use_span_with_array( array, span( array, 3 ) ); + constexpr int s3 = use_fixed_span_with_array( array, span( array ) ); + EXPECT( (r7 | r8 | r9) == 0 ); + EXPECT( s3 == 0 ); +# endif +#endif +} + +CASE( "span<>: Allows to construct from a std::array<> with const data (C++11)" ) +{ +#if gsl_HAVE( ARRAY ) + std::array<const int,9> arr = {{ 1, 2, 3, 4, 5, 6, 7, 8, 9, }}; + + span<const int> v( arr ); + + EXPECT( std::equal( v.begin(), v.end(), arr.begin() ) ); +#else + EXPECT( !!"std::array<> is not available (no C++11)" ); +#endif +} + +CASE( "span<>: Allows to construct from a container (std::vector<>)" ) +{ + std::vector<int> vec = vector_iota(10); + +#if gsl_HAVE( CONSTRAINED_SPAN_CONTAINER_CTOR ) || gsl_HAVE( UNCONSTRAINED_SPAN_CONTAINER_CTOR ) + span< int > v ( vec ); + span<const int > cv( vec ); + span< int, 10> w ( vec ); + span<const int, 10> cw( vec ); + + EXPECT( std::equal( v.begin(), v.end(), vec.begin() ) ); + EXPECT( std::equal( cv.begin(), cv.end(), vec.begin() ) ); + EXPECT( std::equal( w.begin(), w.end(), vec.begin() ) ); + EXPECT( std::equal( cw.begin(), cw.end(), vec.begin() ) ); +#else + EXPECT( !!"(un)constrained construction from container is not available" ); +#endif +} + +CASE( "span<>: Allows to construct from a temporary container (potentially dangerous)" ) +{ +#if gsl_HAVE( CONSTRAINED_SPAN_CONTAINER_CTOR ) || gsl_HAVE( UNCONSTRAINED_SPAN_CONTAINER_CTOR ) + std::vector<int> vec = vector_iota( 10 ); + + EXPECT( std::equal( vec.begin(), vec.end(), span<const int>( vector_iota(10) ).begin() ) ); + EXPECT( std::equal( vec.begin(), vec.end(), span<const int, 10>( vector_iota(10) ).begin() ) ); +#else + EXPECT( !!"(un)constrained construction from container is not available" ); +#endif +} + +CASE( "span<>: Allows to tag-construct from a container (std::vector<>)" ) +{ +#if gsl_FEATURE_TO_STD( WITH_CONTAINER ) + std::vector<int> vec = vector_iota(10); + span< int> v ( with_container, vec ); + span<const int> cv( with_container, vec ); + span< int, 10> w ( with_container, vec ); + span<const int, 10> cw( with_container, vec ); + + EXPECT( std::equal( v.begin(), v.end(), vec.begin() ) ); + EXPECT( std::equal( cv.begin(), cv.end(), vec.begin() ) ); + EXPECT( std::equal( w.begin(), w.end(), vec.begin() ) ); + EXPECT( std::equal( cw.begin(), cw.end(), vec.begin() ) ); +#else + EXPECT( !!"with_container is not available (gsl_FEATURE_WITH_CONTAINER_TO_STD)" ); +#endif +} + +CASE( "span<>: Allows to tag-construct from a temporary container (potentially dangerous)" ) +{ +#if gsl_FEATURE_TO_STD( WITH_CONTAINER ) + std::vector<int> vec = vector_iota(10); + + EXPECT( std::equal( vec.begin(), vec.end(), span<const int>( with_container, vector_iota( 10 ) ).begin() ) ); + EXPECT( std::equal( vec.begin(), vec.end(), span<const int, 10>( with_container, vector_iota( 10 ) ).begin() ) ); +#else + EXPECT( !!"with_container is not available (gsl_FEATURE_WITH_CONTAINER_TO_STD)" ); +#endif +} + +CASE( "span<>: Allows to default construct in a constexpr context") +{ +#if gsl_HAVE( CONSTEXPR_11 ) + constexpr auto spn = gsl_lite::span<int>{ }; + constexpr auto spn2 = gsl_lite::span<int, 0>{ }; + EXPECT( spn.size() == size_type( 0 ) ); + EXPECT( spn2.size() == size_type( 0 ) ); +#else + EXPECT( !!"construction in a constexpr context is not available (C++11)"); +#endif +} + +CASE( "span<>: Allows to copy-construct from another span of the same type" ) +{ + int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, }; + span< int> v ( arr ); + span<const int> cv( arr ); + span< int, 9> w ( arr ); + span<const int, 9> cw( arr ); + + span< int> x ( v ); + span<const int> cx( w ); + span< int, 9> y ( v ); + span<const int, 9> cy( w ); + + EXPECT( std::equal( x.begin(), x.end(), arr ) ); + EXPECT( std::equal( cx.begin(), cx.end(), arr ) ); + EXPECT( std::equal( y.begin(), y.end(), arr ) ); + EXPECT( std::equal( cy.begin(), cy.end(), arr ) ); +} + +CASE( "span<>: Allows to copy-construct from another span of a compatible type" ) +{ + int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, }; + span< int> v ( arr ); + span<const int> cv( arr ); + span< int, 9> w ( arr ); + span<const int, 9> cw( arr ); + + span<const volatile int> x1( v ); + span<const volatile int> x2( cv ); + span<const volatile int> x3( w ); + span<const volatile int> x4( cw ); + span<const volatile int, 9> y1( v ); + span<const volatile int, 9> y2( cv ); + span<const volatile int, 9> y3( v ); + span<const volatile int, 9> y4( cv ); + +#if !gsl_BETWEEN( gsl_COMPILER_APPLECLANG_VERSION, 1, 1500 ) + EXPECT( std::equal( x1.begin(), x1.end(), arr ) ); + EXPECT( std::equal( x2.begin(), x2.end(), arr ) ); + EXPECT( std::equal( x3.begin(), x3.end(), arr ) ); + EXPECT( std::equal( x4.begin(), x4.end(), arr ) ); + EXPECT( std::equal( y1.begin(), y1.end(), arr ) ); + EXPECT( std::equal( y2.begin(), y2.end(), arr ) ); + EXPECT( std::equal( y3.begin(), y3.end(), arr ) ); + EXPECT( std::equal( y4.begin(), y4.end(), arr ) ); +#endif // !gsl_BETWEEN( gsl_COMPILER_APPLECLANG_VERSION, 1, 1500 ) +} + +CASE( "span<>: Allows to move-construct from another span of the same type (C++11)" ) +{ +#if gsl_STDLIB_CPP11_OR_GREATER + int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, }; + + span< int> v (( span< int> ( arr ) )); +// span< int> w (( span<const int> ( arr ) )); + span<const int> cv(( span< int> ( arr ) )); + span<const int> cw(( span<const int> ( arr ) )); + span< int, 9> x (( span< int, 9>( arr ) )); +// span< int, 9> y (( span<const int, 9>( arr ) )); + span<const int, 9> cx(( span< int, 9>( arr ) )); + span<const int, 9> cy(( span<const int, 9>( arr ) )); + + EXPECT( std::equal( v.begin(), v.end(), arr ) ); + EXPECT( std::equal( cv.begin(), cv.end(), arr ) ); + EXPECT( std::equal( cw.begin(), cw.end(), arr ) ); + EXPECT( std::equal( x.begin(), x.end(), arr ) ); + EXPECT( std::equal( cx.begin(), cx.end(), arr ) ); + EXPECT( std::equal( cy.begin(), cy.end(), arr ) ); +#else + EXPECT( !!"move-semantics are not available (no C++11)" ); +#endif +} + +CASE( "span<>: Allows to copy-assign from another span of the same type" ) +{ + int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, }; + int arr2[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, }; + span< int> x( arr ); + span< int, 9> y( arr ); + span< int> s( arr2 ); + span<const int> t( arr2 ); + span< int, 9> u( arr2 ); + span<const int, 9> v( arr2 ); + + s = x; + t = x; + u = y; + v = y; + + EXPECT( std::equal( s.begin(), s.end(), arr ) ); + EXPECT( std::equal( t.begin(), t.end(), arr ) ); + EXPECT( std::equal( u.begin(), u.end(), arr ) ); + EXPECT( std::equal( v.begin(), v.end(), arr ) ); +} + +CASE( "span<>: Allows to move-assign from another span of the same type (C++11)" ) +{ +#if gsl_STDLIB_CPP11_OR_GREATER + int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, }; + int arr2[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, }; + span< int> s( arr2 ); + span<const int> t( arr2 ); + span< int, 9> u( arr2 ); + span<const int, 9> v( arr2 ); + + s = span<int>( arr ); + t = span<const int>( arr ); + u = span<int, 9>( arr ); + v = span<const int, 9>( arr ); + + EXPECT( std::equal( s.begin(), s.end(), arr ) ); + EXPECT( std::equal( t.begin(), t.end(), arr ) ); + EXPECT( std::equal( u.begin(), u.end(), arr ) ); + EXPECT( std::equal( v.begin(), v.end(), arr ) ); +#else + EXPECT( !!"move-semantics are not available (no C++11)" ); +#endif +} + +CASE( "span<>: Allows to create a sub span of the first n elements" ) +{ + int arr[] = { 1, 2, 3, 4, 5, }; + span<int> v( arr ); + span<int, 5> w( arr ); + size_type count = 3; + + span< int> s1 = v.first( count ); + span<const int> t1 = v.first( count ); + span< int> s2 = w.first( count ); + span<const int> t2 = w.first( count ); + span< int, 3> s3 = v.first<3>( ); + span<const int, 3> t3 = v.first<3>( ); + span< int, 3> s4 = w.first<3>( ); + span<const int, 3> t4 = w.first<3>( ); + + EXPECT( s1.size() == count ); + EXPECT( t1.size() == count ); + EXPECT( s2.size() == count ); + EXPECT( t2.size() == count ); + EXPECT( s3.size() == count ); + EXPECT( t3.size() == count ); + EXPECT( s4.size() == count ); + EXPECT( t4.size() == count ); + EXPECT( std::equal( s1.begin(), s1.end(), arr ) ); + EXPECT( std::equal( t1.begin(), t1.end(), arr ) ); + EXPECT( std::equal( s2.begin(), s2.end(), arr ) ); + EXPECT( std::equal( t2.begin(), t2.end(), arr ) ); + EXPECT( std::equal( s3.begin(), s3.end(), arr ) ); + EXPECT( std::equal( t3.begin(), t3.end(), arr ) ); + EXPECT( std::equal( s4.begin(), s4.end(), arr ) ); + EXPECT( std::equal( t4.begin(), t4.end(), arr ) ); +} + +CASE( "span<>: Allows to create a sub span of the last n elements" ) +{ + int arr[] = { 1, 2, 3, 4, 5, }; + span<int> v( arr ); + span<int, 5> w( arr ); + size_type count = 3; + + span< int> s1 = v.last( count ); + span<const int> t1 = v.last( count ); + span< int> s2 = w.last( count ); + span<const int> t2 = w.last( count ); + span< int, 3> s3 = v.last<3>( ); + span<const int, 3> t3 = v.last<3>( ); + span< int, 3> s4 = w.last<3>( ); + span<const int, 3> t4 = w.last<3>( ); + + EXPECT( s1.size() == count ); + EXPECT( t1.size() == count ); + EXPECT( s2.size() == count ); + EXPECT( t2.size() == count ); + EXPECT( s3.size() == count ); + EXPECT( t3.size() == count ); + EXPECT( s4.size() == count ); + EXPECT( t4.size() == count ); + EXPECT( std::equal( s1.begin(), s1.end(), arr + v.size() - count ) ); + EXPECT( std::equal( t1.begin(), t1.end(), arr + v.size() - count ) ); + EXPECT( std::equal( s2.begin(), s2.end(), arr + v.size() - count ) ); + EXPECT( std::equal( t2.begin(), t2.end(), arr + v.size() - count ) ); + EXPECT( std::equal( s3.begin(), s3.end(), arr + v.size() - count ) ); + EXPECT( std::equal( t3.begin(), t3.end(), arr + v.size() - count ) ); + EXPECT( std::equal( s4.begin(), s4.end(), arr + v.size() - count ) ); + EXPECT( std::equal( t4.begin(), t4.end(), arr + v.size() - count ) ); +} + +CASE( "span<>: Allows to create a sub span starting at a given offset" ) +{ + int arr[] = { 1, 2, 3, }; + span<int> v( arr ); + span<int, 3> w( arr ); + size_type offset = 1; + + span< int> s1 = v.subspan( offset ); + span<const int> t1 = v.subspan( offset ); + span< int> s2 = w.subspan( offset ); + span<const int> t2 = w.subspan( offset ); + span< int> s3 = v.subspan<1>( ); + span<const int> t3 = v.subspan<1>( ); + span< int, 2> s4 = w.subspan<1>( ); + span<const int, 2> t4 = w.subspan<1>( ); + + EXPECT( s1.size() == v.size() - offset ); + EXPECT( t1.size() == v.size() - offset ); + EXPECT( s2.size() == v.size() - offset ); + EXPECT( t2.size() == v.size() - offset ); + EXPECT( s3.size() == v.size() - offset ); + EXPECT( t3.size() == v.size() - offset ); + EXPECT( s4.size() == v.size() - offset ); + EXPECT( t4.size() == v.size() - offset ); + EXPECT( std::equal( s1.begin(), s1.end(), arr + offset ) ); + EXPECT( std::equal( t1.begin(), t1.end(), arr + offset ) ); + EXPECT( std::equal( s2.begin(), s2.end(), arr + offset ) ); + EXPECT( std::equal( t2.begin(), t2.end(), arr + offset ) ); + EXPECT( std::equal( s3.begin(), s3.end(), arr + offset ) ); + EXPECT( std::equal( t3.begin(), t3.end(), arr + offset ) ); + EXPECT( std::equal( s4.begin(), s4.end(), arr + offset ) ); + EXPECT( std::equal( t4.begin(), t4.end(), arr + offset ) ); +} + +CASE( "span<>: Allows to create a sub span starting at a given offset with a given length" ) +{ + int arr[] = { 1, 2, 3, }; + span<int> v( arr ); + span<int, 3> w( arr ); + size_type offset = 1; + size_type length = 1; + + span< int> s1 = v.subspan( offset, length ); + span<const int> t1 = v.subspan( offset, length ); + span< int> s2 = w.subspan( offset, length ); + span<const int> t2 = w.subspan( offset, length ); + span< int, 1> s3 = v.subspan<1, 1>( ); + span<const int, 1> t3 = v.subspan<1, 1>( ); + span< int, 1> s4 = w.subspan<1, 1>( ); + span<const int, 1> t4 = w.subspan<1, 1>( ); + + EXPECT( s1.size() == length ); + EXPECT( t1.size() == length ); + EXPECT( s2.size() == length ); + EXPECT( t2.size() == length ); + EXPECT( s3.size() == length ); + EXPECT( t3.size() == length ); + EXPECT( s4.size() == length ); + EXPECT( t4.size() == length ); + EXPECT( std::equal( s1.begin(), s1.end(), arr + offset ) ); + EXPECT( std::equal( t1.begin(), t1.end(), arr + offset ) ); + EXPECT( std::equal( s2.begin(), s2.end(), arr + offset ) ); + EXPECT( std::equal( t2.begin(), t2.end(), arr + offset ) ); + EXPECT( std::equal( s3.begin(), s3.end(), arr + offset ) ); + EXPECT( std::equal( t3.begin(), t3.end(), arr + offset ) ); + EXPECT( std::equal( s4.begin(), s4.end(), arr + offset ) ); + EXPECT( std::equal( t4.begin(), t4.end(), arr + offset ) ); +} + +CASE( "span<>: Allows to create an empty sub span at full offset" ) +{ + int arr[] = { 1, 2, 3, }; + span<int> v( arr ); + span<int, 3> w( arr ); + size_type offset = v.size(); + + span< int> s1 = v.subspan( offset ); + span<const int> t1 = v.subspan( offset ); + span< int> s2 = w.subspan( offset ); + span<const int> t2 = w.subspan( offset ); + span< int> s3 = v.subspan<3>( ); + span<const int> t3 = v.subspan<3>( ); + span< int, 0> s4 = w.subspan<3>( ); + span<const int, 0> t4 = w.subspan<3>( ); + + EXPECT( s1.empty() ); + EXPECT( t1.empty() ); + EXPECT( s2.empty() ); + EXPECT( t2.empty() ); + EXPECT( s3.empty() ); + EXPECT( t3.empty() ); + EXPECT( s4.empty() ); + EXPECT( t4.empty() ); +} + +CASE( "span<>: Allows to create an empty sub span at full offset with zero length" ) +{ + int arr[] = { 1, 2, 3, }; + span<int> v( arr ); + span<int, 3> w( arr ); + size_type offset = v.size(); + size_type length = 0; + + span< int> s1 = v.subspan( offset, length ); + span<const int> t1 = v.subspan( offset, length ); + span< int> s2 = w.subspan( offset, length ); + span<const int> t2 = w.subspan( offset, length ); + span< int> s3 = v.subspan<3, 0>( ); + span<const int> t3 = v.subspan<3, 0>( ); + span< int, 0> s4 = w.subspan<3, 0>( ); + span<const int, 0> t4 = w.subspan<3, 0>( ); + + EXPECT( s1.empty() ); + EXPECT( t1.empty() ); + EXPECT( s2.empty() ); + EXPECT( t2.empty() ); + EXPECT( s3.empty() ); + EXPECT( t3.empty() ); + EXPECT( s4.empty() ); + EXPECT( t4.empty() ); +} + +CASE( "span<>: Allows forward iteration" ) +{ + int arr[] = { 1, 2, 3, }; + span<int> v( arr ); + span<int, 3> w( arr ); + + for ( span<int>::iterator pos = v.begin(); pos != v.end(); ++pos ) + { + EXPECT( *pos == arr[ std::distance( v.begin(), pos )] ); + } + for ( span<int, 3>::iterator pos = w.begin(); pos != w.end(); ++pos ) + { + EXPECT( *pos == arr[ std::distance( w.begin(), pos )] ); + } +} + +CASE( "span<>: Allows const forward iteration" ) +{ + int arr[] = { 1, 2, 3, }; + span<int> v( arr ); + span<int, 3> w( arr ); + + for ( span<int>::const_iterator pos = v.cbegin(); pos != v.cend(); ++pos ) + { + EXPECT( *pos == arr[ std::distance( v.cbegin(), pos )] ); + } + for ( span<int, 3>::const_iterator pos = w.cbegin(); pos != w.cend(); ++pos ) + { + EXPECT( *pos == arr[ std::distance( w.cbegin(), pos )] ); + } +} + +CASE( "span<>: Allows reverse iteration" ) +{ + int arr[] = { 1, 2, 3, }; + span<int> v( arr ); + span<int, 3> w( arr ); + + for ( span<int>::reverse_iterator pos = v.rbegin(); pos != v.rend(); ++pos ) + { + size_t dist = narrow_failfast<size_t>( std::distance(v.rbegin(), pos) ); + EXPECT( *pos == arr[ v.size() - 1 - dist ] ); + } + for ( span<int, 3>::reverse_iterator pos = w.rbegin(); pos != w.rend(); ++pos ) + { + size_t dist = narrow_failfast<size_t>( std::distance(v.rbegin(), pos) ); + EXPECT( *pos == arr[ w.size() - 1 - dist ] ); + } +} + +CASE( "span<>: Allows const reverse iteration" ) +{ + int arr[] = { 1, 2, 3, }; + const span<int> v( arr ); + const span<int, 3> w( arr ); + + for ( span<int>::const_reverse_iterator pos = v.crbegin(); pos != v.crend(); ++pos ) + { + size_t dist = narrow_failfast<size_t>( std::distance(v.crbegin(), pos) ); + EXPECT( *pos == arr[ v.size() - 1 - dist ] ); + } + for ( span<int>::const_reverse_iterator pos = w.crbegin(); pos != w.crend(); ++pos ) + { + size_t dist = narrow_failfast<size_t>( std::distance(v.crbegin(), pos) ); + EXPECT( *pos == arr[ w.size() - 1 - dist ] ); + } +} + +CASE( "span<>: Allows to observe an element via array indexing" ) +{ + int arr[] = { 1, 2, 3, }; + span<int> v ( arr ); + span<int> const cv( arr ); + span<int, 3> w ( arr ); + span<int, 3> const cw( arr ); + + for ( size_type i = 0; i < v.size(); ++i ) + { + EXPECT( v[i] == arr[i] ); + EXPECT( cv[i] == arr[i] ); + EXPECT( &v[i] == &arr[i] ); + EXPECT( &cv[i] == &arr[i] ); + EXPECT( w[i] == arr[i] ); + EXPECT( cw[i] == arr[i] ); + EXPECT( &w[i] == &arr[i] ); + EXPECT( &cw[i] == &arr[i] ); + } +} + +CASE( "span<>: Allows to observe an element via front() and back()" ) +{ + int arr[] = { 1, 2, 3, }; + span<int> v ( arr ); + span<int> const cv( arr ); + span<int, 3> w ( arr ); + span<int, 3> const cw( arr ); + + + EXPECT( v.front() == arr[0] ); + EXPECT( &v.front() == &arr[0] ); + EXPECT( cv.front() == arr[0] ); + EXPECT( &cv.front() == &arr[0] ); + EXPECT( w.back() == arr[2] ); + EXPECT( &w.back() == &arr[2] ); + EXPECT( cw.back() == arr[2] ); + EXPECT( &cw.back() == &arr[2] ); +} + +CASE( "span<>: Allows to observe an element via data()" ) +{ + int arr[] = { 1, 2, 3, }; + span<int> v ( arr ); + span<int> const cv( arr ); + span<int, 3> w ( arr ); + span<int, 3> const cw( arr ); + + EXPECT( *v.data() == *v.begin() ); + EXPECT( v.data() == &*v.begin() ); + EXPECT( *cv.data() == *v.begin() ); + EXPECT( cv.data() == &*v.begin() ); + EXPECT( *w.data() == *v.begin() ); + EXPECT( w.data() == &*v.begin() ); + EXPECT( *cw.data() == *v.begin() ); + EXPECT( cw.data() == &*v.begin() ); + + for ( size_type i = 0; i < v.size(); ++i ) + { + EXPECT( v.data()[i] == arr[i] ); + EXPECT( cv.data()[i] == arr[i] ); + EXPECT( w.data()[i] == arr[i] ); + EXPECT( cw.data()[i] == arr[i] ); + } +} + +CASE( "span<>: Allows to change an element via array indexing" ) +{ + int arr[] = { 1, 2, 3, 4, 5, }; + span<int> v( arr ); + span<int> const cv( arr ); + span<int, 5> w( arr ); + span<int, 5> const cw( arr ); + + v[1] = 22; + cv[2] = 33; + w[3] = 44; + cw[4] = 55; + + EXPECT( 22 == arr[1] ); + EXPECT( 33 == arr[2] ); + EXPECT( 44 == arr[3] ); + EXPECT( 55 == arr[4] ); +} + +CASE( "span<>: Allows to change an element via front() and back()" ) +{ + int arr[] = { 1, 2, 3, }; + int arr2[] = { 1, 2, 3, }; + int arr3[] = { 1, 2, 3, }; + int arr4[] = { 1, 2, 3, }; + span<int> v( arr ); + span<int> const cv( arr2 ); + span<int, 3> w( arr3 ); + span<int, 3> const cw( arr4 ); + + v.front() = 11; + v.back() = 33; + cv.front() = 11; + cv.back() = 33; + w.front() = 11; + w.back() = 33; + cw.front() = 11; + cw.back() = 33; + + EXPECT( 11 == arr[0] ); + EXPECT( 33 == arr[2] ); + EXPECT( 11 == arr2[0] ); + EXPECT( 33 == arr2[2] ); + EXPECT( 11 == arr3[0] ); + EXPECT( 33 == arr3[2] ); + EXPECT( 11 == arr4[0] ); + EXPECT( 33 == arr4[2] ); +} + +CASE( "span<>: Allows to change an element via data()" ) +{ + int arr[] = { 1, 2, 3, }; + span<int> v( arr ); + span<int> const cv( arr ); + span<int, 3> w( arr ); + span<int, 3> const cw( arr ); + + *v.data() = 22; + EXPECT( 22 == *cv.data() ); + *cv.data() = 33; + EXPECT( 33 == *v.data() ); + *w.data() = 44; + EXPECT( 44 == *cw.data() ); + *cw.data() = 55; + EXPECT( 55 == *w.data() ); +} + +#if gsl_CONFIG( ALLOWS_SPAN_COMPARISON ) +CASE( "span<>: Allows to compare equal to another span of the same type" ) +{ + int a[] = { 1 }, b[] = { 2 }, c[] = { 1, 2 }; + span<int> va( a ); + span<int> vb( b ); + span<int> vc( c ); + span<int, 1> wa( a ); + span<int, 1> wb( b ); + span<int, 2> wc( c ); + + EXPECT( va == va ); + EXPECT_NOT( vb == va ); + EXPECT_NOT( vc == va ); + EXPECT( wa == wa ); + EXPECT( va == wa ); + EXPECT_NOT( vb == wa ); + EXPECT_NOT( vc == wa ); +} + +CASE( "span<>: Allows to compare unequal to another span of the same type" ) +{ + int a[] = { 1 }, b[] = { 2 }, c[] = { 1, 2 }; + span<int> va( a ); + span<int> vb( b ); + span<int> vc( c ); + span<int, 1> wa( a ); + span<int, 1> wb( b ); + span<int, 2> wc( c ); + + EXPECT_NOT( va != va ); + EXPECT( vb != va ); + EXPECT( vc != va ); + EXPECT( vc != va ); + EXPECT_NOT( wa != wa ); + EXPECT( wa != wb ); + EXPECT_NOT( va != wa ); + EXPECT( vb != wa ); + EXPECT( vc != wa ); +} + +CASE( "span<>: Allows to compare less than another span of the same type" ) +{ + int a[] = { 1 }, b[] = { 2 }, c[] = { 1, 2 }; + span<int> va( a ); + span<int> vb( b ); + span<int> vc( c ); + span<int, 1> wa( a ); + span<int, 1> wb( b ); + span<int, 2> wc( c ); + + EXPECT_NOT( va < va ); + EXPECT( va < vb ); + EXPECT( va < vc ); + EXPECT_NOT( wa < wa ); + EXPECT( wa < wb ); + EXPECT( wa < wc ); + EXPECT_NOT( va < wa ); + EXPECT( va < wb ); + EXPECT( va < wc ); +} + +CASE( "span<>: Allows to compare less than or equal to another span of the same type" ) +{ + int a[] = { 1 }, b[] = { 2 }, c[] = { 1, 2 }; + span<int> va( a ); + span<int> vb( b ); + span<int> vc( c ); + span<int, 1> wa( a ); + span<int, 1> wb( b ); + span<int, 2> wc( c ); + + EXPECT_NOT( vb <= va ); + EXPECT( va <= vb ); + EXPECT( va <= vc ); + EXPECT_NOT( wb <= wa ); + EXPECT( wa <= wb ); + EXPECT( wa <= wc ); + EXPECT_NOT( vb <= wa ); + EXPECT( va <= wb ); + EXPECT( va <= wc ); +} + +CASE( "span<>: Allows to compare greater than another span of the same type" ) +{ + int a[] = { 1 }, b[] = { 2 }, c[] = { 1, 2 }; + span<int> va( a ); + span<int> vb( b ); + span<int> vc( c ); + span<int, 1> wa( a ); + span<int, 1> wb( b ); + span<int, 2> wc( c ); + + EXPECT_NOT( va > va ); + EXPECT( vb > va ); + EXPECT( vc > va ); + EXPECT_NOT( wa > wa ); + EXPECT( wb > wa ); + EXPECT( wc > wa ); + EXPECT_NOT( va > wa ); + EXPECT( vb > wa ); + EXPECT( vc > wa ); +} + +CASE( "span<>: Allows to compare greater than or equal to another span of the same type" ) +{ + int a[] = { 1 }, b[] = { 2 }, c[] = { 1, 2 }; + span<int> va( a ); + span<int> vb( b ); + span<int> vc( c ); + span<int, 1> wa( a ); + span<int, 1> wb( b ); + span<int, 2> wc( c ); + + EXPECT_NOT( va >= vb ); + EXPECT( vb >= va ); + EXPECT( vc >= va ); + EXPECT_NOT( wa >= wb ); + EXPECT( wb >= wa ); + EXPECT( wc >= wa ); + EXPECT_NOT( va >= wb ); + EXPECT( vb >= wa ); + EXPECT( vc >= wa ); +} + +CASE( "span<>: Allows to compare to another span of the same type and different cv-ness (non-standard)" ) +{ +#if gsl_CONFIG( ALLOWS_NONSTRICT_SPAN_COMPARISON ) + int aa[] = { 1 }, bb[] = { 2 }; + span< int> a( aa ); + span< const int> ca( aa ); + span<volatile int> va( aa ); + span< int> b( bb ); + span< const int> cb( bb ); + span< int, 1> af( aa ); + span< const int, 1> caf( aa ); + span<volatile int, 1> vaf( aa ); + span< int, 1> bf( bb ); + span< const int, 1> cbf( bb ); + + EXPECT( va == ca ); + EXPECT( a == va ); + EXPECT( vaf == caf ); + EXPECT( af == vaf ); + EXPECT( va == caf ); + EXPECT( a == vaf ); + + EXPECT( a == ca ); + EXPECT( a != cb ); + EXPECT( a <= cb ); + EXPECT( a < cb ); + EXPECT( b >= ca ); + EXPECT( b > ca ); + EXPECT( af == ca ); + EXPECT( af != cb ); + EXPECT( af <= cb ); + EXPECT( af < cb ); + EXPECT( bf >= ca ); + EXPECT( bf > ca ); +#else + EXPECT( !!"span<>: cannot compare different types (gsl_CONFIG_ALLOWS_NONSTRICT_SPAN_COMPARISON=0)" ); +#endif +} + +CASE( "span<>: Allows to compare empty spans as equal" ) +{ + int a; + + span<int> p; + span<int> q; + span<int> r( &a, size_type( 0 ) ); + span<int, 0> s; + span<int, 0> t( &a, size_type( 0 ) ); + + EXPECT( p == q ); + EXPECT( p == r ); + EXPECT( p == s ); + EXPECT( p == t ); + EXPECT( s == t ); +} +#endif // gsl_CONFIG( ALLOWS_SPAN_COMPARISON ) + +CASE( "span<>: Allows to test for empty span via empty(), empty case" ) +{ + span<int> v; + span<int, 0> w; + + EXPECT( v.empty() ); + EXPECT( w.empty() ); +} + +CASE( "span<>: Allows to test for empty span via empty(), non-empty case" ) +{ + int a[] = { 1 }; + span<int> v( a ); + span<int, 1> w( a ); + + EXPECT_NOT( v.empty() ); + EXPECT_NOT( w.empty() ); +} + +CASE( "span<>: Allows to obtain the number of elements via size(), as configured" ) +{ + int a[] = { 1, 2, 3, }; + int b[] = { 1, 2, 3, 4, 5, }; + + span<int> z; + span<int> va( a ); + span<int> vb( b ); + span<int, 0> y; + span<int, 3> wa( a ); + span<int, 5> wb( b ); + + EXPECT( va.size() == size_type( gsl_DIMENSION_OF( a ) ) ); + EXPECT( vb.size() == size_type( gsl_DIMENSION_OF( b ) ) ); + EXPECT( wa.size() == size_type( gsl_DIMENSION_OF( a ) ) ); + EXPECT( wb.size() == size_type( gsl_DIMENSION_OF( b ) ) ); + EXPECT( z.size() == size_type( 0 ) ); + EXPECT( y.size() == size_type( 0 ) ); +} + +CASE( "span<>: Allows to obtain the number of elements via ssize(), signed" ) +{ + int a[] = { 1, 2, 3, }; + int b[] = { 1, 2, 3, 4, 5, }; + + span<int> z; + span<int> va( a ); + span<int> vb( b ); + span<int, 0> y; + span<int, 3> wa( a ); + span<int, 5> wb( b ); + + EXPECT( va.ssize() == difference_type( gsl_DIMENSION_OF( a ) ) ); + EXPECT( vb.ssize() == difference_type( gsl_DIMENSION_OF( b ) ) ); + EXPECT( wa.ssize() == difference_type( gsl_DIMENSION_OF( a ) ) ); + EXPECT( wb.ssize() == difference_type( gsl_DIMENSION_OF( b ) ) ); + EXPECT( z.ssize() == difference_type( 0 ) ); + EXPECT( y.ssize() == difference_type( 0 ) ); +} + +CASE( "span<>: Allows to obtain the number of bytes via size_bytes()" ) +{ + int a[] = { 1, 2, 3, }; + int b[] = { 1, 2, 3, 4, 5, }; + + span<int> z; + span<int> va( a ); + span<int> vb( b ); + span<int, 0> y; + span<int, 3> wa( a ); + span<int, 5> wb( b ); + + EXPECT( va.size_bytes() == size_type( gsl_DIMENSION_OF( a ) * sizeof(int) ) ); + EXPECT( vb.size_bytes() == size_type( gsl_DIMENSION_OF( b ) * sizeof(int) ) ); + EXPECT( wa.size_bytes() == size_type( gsl_DIMENSION_OF( a ) * sizeof(int) ) ); + EXPECT( wb.size_bytes() == size_type( gsl_DIMENSION_OF( b ) * sizeof(int) ) ); + EXPECT( z.size_bytes() == size_type( 0 ) ); + EXPECT( y.size_bytes() == size_type( 0 ) ); +} + +CASE( "span<>: Allows to swap with another span of the same type" ) +{ + int a[] = { 1, 2, 3, }; + int b[] = { 1, 2, 3, 4, 5, }; + int c[] = { 4, 5, 6, }; + + span<int> va0( a ); + span<int> vb0( b ); + span<int> va( a ); + span<int> vb( b ); + span<int, 3> wa0( a ); + span<int, 3> wc0( c ); + span<int, 3> wa( a ); + span<int, 3> wc( c ); + + va.swap( vb ); + wa.swap( wc ); + + EXPECT( va.data() == vb0.data() ); EXPECT( va.size() == vb0.size() ); + EXPECT( vb.data() == va0.data() ); EXPECT( vb.size() == va0.size() ); + EXPECT( wa.data() == wc0.data() ); EXPECT( wa.size() == wc0.size() ); + EXPECT( wc.data() == wa0.data() ); EXPECT( wc.size() == wa0.size() ); +} + +bool is_little_endian() +{ + union U + { + U() : i(1) {} + int i; + unsigned char c[ sizeof(int) ]; + }; + return 1 != U().c[ sizeof(int) - 1 ]; +} + +CASE( "span<>: Allows to view the elements as read-only bytes" ) +{ +#if gsl_FEATURE( BYTE ) +# if gsl_HAVE( SIZED_TYPES ) + typedef int32_t type; +# else + typedef int type; +# endif + typedef gsl_lite::byte gyte; + + EXPECT( sizeof( type ) == size_t( 4 ) ); + + type a[] = { 0x12345678, }; + gyte be[] = { to_byte(0x12), to_byte(0x34), to_byte(0x56), to_byte(0x78), }; + gyte le[] = { to_byte(0x78), to_byte(0x56), to_byte(0x34), to_byte(0x12), }; + + gyte * b = is_little_endian() ? le : be; + + span<type> va( a ); + span<const gyte> vc( as_bytes( va ) ); + + EXPECT( vc[0] == b[0] ); + EXPECT( vc[1] == b[1] ); + EXPECT( vc[2] == b[2] ); + EXPECT( vc[3] == b[3] ); + +#endif // gsl_FEATURE( BYTE ) +} + +CASE( "span<>: Allows to view and change the elements as writable bytes" ) +{ +#if gsl_FEATURE( BYTE ) +# if gsl_HAVE( SIZED_TYPES ) + typedef int32_t type; +# else + typedef int type; +# endif + typedef gsl_lite::byte gyte; + + EXPECT( sizeof(type) == size_t( 4 ) ); + + { + type a[] = { 0x0, }; + span<type> va( a ); + span<gyte> vc( as_writable_bytes(va) ); + + for ( size_t i = 0; i < sizeof(type); ++i ) + { + EXPECT( vc[i] == to_byte(0) ); + } + + vc[0] = to_byte(0x42); + + EXPECT( vc[0] == to_byte(0x42) ); + for ( size_t i = 1; i < sizeof(type); ++i ) + { + EXPECT( vc[i] == to_byte(0) ); + } + } + +#endif // gsl_FEATURE( BYTE ) +} + +CASE( "span<>: Allows to view the elements as a span of another type" ) +{ +#if ! gsl_DEPRECATE_TO_LEVEL( 9 ) +# if gsl_HAVE( SIZED_TYPES ) + typedef int32_t type1; + typedef int16_t type2; +# else + typedef int type1; + typedef short type2; +# endif + EXPECT( sizeof( type1 ) == size_t( 4 ) ); + EXPECT( sizeof( type2 ) == size_t( 2 ) ); + + type1 a[] = { 0x12345678, }; + type2 be[] = { type2(0x1234), type2(0x5678), }; + type2 le[] = { type2(0x5678), type2(0x1234), }; + + type2 * b = is_little_endian() ? le : be; + + span<type1> va( a ); + span<type2> vb( va.as_span<type2>() ); + + EXPECT( vb[0] == b[0] ); + EXPECT( vb[1] == b[1] ); +#endif // ! gsl_DEPRECATE_TO_LEVEL( 9 ) +} + +CASE( "span<>: Allows to change the elements from a span of another type" ) +{ +#if ! gsl_DEPRECATE_TO_LEVEL( 9 ) +# if gsl_HAVE( SIZED_TYPES ) + typedef int32_t type1; + typedef int16_t type2; +# else + typedef int type1; + typedef short type2; +# endif + EXPECT( sizeof( type1 ) == size_t( 4 ) ); + EXPECT( sizeof( type2 ) == size_t( 2 ) ); + + type1 a[] = { 0x0, }; + + span<type1> va( a ); + span<type2> vb( va.as_span<type2>() ); + + {for ( size_t i = 0; i < sizeof(type2); ++i ) EXPECT( vb[i] == type2(0) ); } + + vb[0] = 0x42; + + EXPECT( vb[0] == type2(0x42) ); + {for ( size_t i = 1; i < sizeof(type2); ++i ) EXPECT( vb[i] == type2(0) ); } +#endif // ! gsl_DEPRECATE_TO_LEVEL( 9 ) +} + +CASE( "span<>: Allows default construction of iterators" ) +{ + span<int>::iterator it1; + span<int>::iterator it2; + EXPECT(it1 == it2); +} + +CASE( "span<>: Allows comparison of iterators from same span" ) +{ + int a[] = {1, 2, 3, 4}; + + span<int> s = a; + span<int>::iterator it = s.begin(); + span<int>::iterator it2 = it + 1; + + EXPECT(it == it); + EXPECT(it == s.begin()); + EXPECT(s.begin() == it); + + EXPECT(it != it2); + EXPECT(it2 != it); + EXPECT(it != s.end()); + EXPECT(it2 != s.end()); + EXPECT(s.end() != it); + + EXPECT(it < it2); + EXPECT(it <= it2); + EXPECT(it2 <= s.end()); + EXPECT(it < s.end()); + + EXPECT(it2 > it); + EXPECT(it2 >= it); + EXPECT(s.end() > it2); + EXPECT(s.end() >= it2); +} + +CASE( "span<>: Terminates comparison of iterators from different spans" ) +{ + struct F { + static void blow() + { + int a[] = {1, 2, 3, 4}; + int b[] = {1, 2, 3, 4}; + span<int> s( a ); + span<int> s2( b ); + + (void) ( s.begin() == s2.begin() ); + }}; + struct G { + static void blow() + { + int a[] = {1, 2, 3, 4}; + int b[] = {1, 2, 3, 4}; + span<int> s( a ); + span<int> s2( b ); + + (void) ( s.begin() <= s2.begin() ); + }}; + + EXPECT_THROWS( F::blow() ); + EXPECT_THROWS( G::blow() ); +} + +CASE( "span<>: Allows dereferencing iterators" ) +{ + { + int a[] = {1, 2, 3, 4}; + span<int> s = a; + + span<int>::iterator it = s.begin(); +#if gsl_STDLIB_CPP11_OR_GREATER + span<int>::iterator it2 = std::begin(s); +#else // ! gsl_STDLIB_CPP11_OR_GREATER + span<int>::iterator it2 = s.begin(); +#endif // gsl_STDLIB_CPP11_OR_GREATER + EXPECT(it == it2); + + it = s.end(); +#if gsl_STDLIB_CPP11_OR_GREATER + it2 = std::end(s); +#else // ! gsl_STDLIB_CPP11_OR_GREATER + it2 = s.end(); +#endif // gsl_STDLIB_CPP11_OR_GREATER + EXPECT(it == it2); + } + + { + int a[] = {1, 2, 3, 4}; + span<int> s = a; + + span<int>::iterator it = s.begin(); + span<int>::iterator first = it; + EXPECT(it == first); + EXPECT(*it == 1); + + span<int>::iterator beyond = s.end(); + EXPECT(it != beyond); + + EXPECT(beyond - first == difference_type( 4 )); + EXPECT(first - first == difference_type( 0 )); + EXPECT(beyond - beyond == difference_type( 0 )); + + ++it; + EXPECT(it - first == difference_type( 1 )); + EXPECT(*it == 2); + *it = 22; + EXPECT(*it == 22); + EXPECT(beyond - it == difference_type( 3 )); + + it = first; + EXPECT(it == first); + while (it != s.end()) + { + *it = 5; + ++it; + } + + EXPECT(it == beyond); + EXPECT(it - beyond == difference_type( 0 )); + + for (span<int>::const_iterator pos = s.begin(); pos != s.end(); ++pos) + { + EXPECT(*pos == 5); + } + } +} + +CASE( "span<>: Terminates dereferencing past-the-end iterators" ) +{ + int a[] = {1, 2, 3, 4}; + span<int> s = a; + + span<int>::iterator beyond = s.end(); + EXPECT_THROWS(*beyond); +} + +CASE( "span<>: Allows dereferencing reverse iterators" ) +{ + int a[] = {1, 2, 3, 4}; + span<int> s = a; + + span<int>::reverse_iterator it = s.rbegin(); + span<int>::reverse_iterator first = it; + EXPECT(it == first); + EXPECT(*it == 4); + + span<int>::reverse_iterator beyond = s.rend(); + EXPECT(it != beyond); + + EXPECT(beyond - first == difference_type( 4 )); + EXPECT(first - first == difference_type( 0 )); + EXPECT(beyond - beyond == difference_type( 0 )); + + ++it; + EXPECT(it - s.rbegin() == difference_type( 1 )); + EXPECT(*it == 3); + *it = 22; + EXPECT(*it == 22); + EXPECT(beyond - it == difference_type( 3 )); + + it = first; + EXPECT(it == first); + while (it != s.rend()) + { + *it = 5; + ++it; + } + + EXPECT(it == beyond); + EXPECT(it - beyond == difference_type( 0 )); + + for (span<int>::const_reverse_iterator pos = s.rbegin(); pos != s.rend(); ++pos) + { + EXPECT(*pos == 5); + } +} + +CASE( "span<>: Terminates dereferencing past-the-end reverse iterators" ) +{ + struct F { + static void blow() + { + int a[] = {1, 2, 3, 4}; + span<int> s = a; + + span<int>::reverse_iterator beyond = s.rend(); + (void) *beyond; + }}; + + EXPECT_THROWS(F::blow()); +} + +CASE( "span<>: Allows appropriate fixed-size conversions" ) +{ + int arr[] = {1, 2, 3, 4}; + + // converting to a span from an equal size array is ok + span<int, 4> s4 = arr; + EXPECT(s4.size() == size_type( 4 )); + + // converting to dynamic_range is always ok + { + span<int> s = s4; + EXPECT(s.size() == s4.size()); + (void) s; + } + +#if gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) && ! gsl_BETWEEN( gsl_COMPILER_MSVC_VERSION, 1, 140 ) + // initialization or assignment to static span is NOT ok + static_assert( !std::is_convertible< int[4], span<int, 2> >::value, "static assertion failed" ); + static_assert( !std::is_convertible< span<int, 4>, span<int, 2> >::value, "static assertion failed" ); + static_assert( !std::is_convertible< int[2], span<int, 4> >::value, "static assertion failed" ); + static_assert( !std::is_convertible< span<int, 2>, span<int, 4> >::value, "static assertion failed" ); + + // even when done dynamically + static_assert( !std::is_convertible< span<int>, span<int, 2> >::value, "static assertion failed" ); + + // but doing so explicitly is ok + static_assert( std::is_constructible< span<int>, span<int, 2> >::value, "static assertion failed" ); +#endif // gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) && ! gsl_BETWEEN( gsl_COMPILER_MSVC_VERSION, 1, 140 ) + + // you can convert statically + { + const span<int, 2> s2( &arr[0], 2 ); + (void) s2; + } + { + const span<int, 1> s1 = s4.first<1>(); + (void) s1; + } +} + +CASE( "span<>: Terminates inappropriate fixed-size conversions" ) +{ + struct F { + static void blow() + { + int arr2[2] = {1, 2}; + const span<int, 4> s4(arr2, 2); + (void) s4; + }}; + + EXPECT_THROWS( F::blow() ); +} + +CASE( "copy(): Allows to copy a span to another span of the same element type" ) +{ + int a[] = { 1, 2, 3, }; + int b[] = { 0, 0, 0, 0, 0, }; + int c[] = { 0, 0, 0, 0, 0, }; + int d[] = { 0, 0, 0, 0, 0, }; + int e[] = { 0, 0, 0, 0, 0, }; + + span<int> src1( a ); + span<int, 3> src2( a ); + span<int> dst1( b ); + span<int, 5> dst2( c ); + span<int> dst3( d ); + span<int, 5> dst4( e ); + + copy( src1, dst1 ); + copy( src1, dst2 ); + copy( src2, dst3 ); + copy( src2, dst4 ); + + EXPECT( std::equal(src1.begin(), src1.end(), dst1.begin()) ); + EXPECT( std::equal(src1.begin(), src1.end(), dst2.begin()) ); + EXPECT( std::equal(src1.begin(), src1.end(), dst3.begin()) ); + EXPECT( std::equal(src1.begin(), src1.end(), dst4.begin()) ); +} + +CASE( "copy(): Allows to copy a span to another span of a different element type" ) +{ + char a[] = { 'a', 'b', 'c', }; + int b[] = { 0 , 0 , 0 , 0, 0, }; + int c[] = { 0 , 0 , 0 , 0, 0, }; + int d[] = { 0 , 0 , 0 , 0, 0, }; + int e[] = { 0 , 0 , 0 , 0, 0, }; + + span<char> src1( a ); + span<char, 3> src2( a ); + span<int> dst1( b ); + span<int, 5> dst2( c ); + span<int> dst3( d ); + span<int, 5> dst4( e ); + + copy( src1, dst1 ); + copy( src1, dst2 ); + copy( src2, dst3 ); + copy( src2, dst4 ); + + for ( span<int>::size_type i = 0; i < src1.size(); ++i ) + { + EXPECT( src1[i] == dst1[i] ); + EXPECT( src1[i] == dst2[i] ); + EXPECT( src1[i] == dst3[i] ); + EXPECT( src1[i] == dst4[i] ); + } +} + +CASE( "size(): Allows to obtain the number of elements in span via size(span), unsigned" ) +{ + int a[] = { 1, 2, 3, }; + int b[] = { 1, 2, 3, 4, 5, }; + + span<int> z; + span<int> va( a ); + span<int> vb( b ); + span<int, 0> y; + span<int, 3> wa( a ); + span<int, 5> wb( b ); + + EXPECT( size( va ) == size_type( gsl_DIMENSION_OF( a ) ) ); + EXPECT( size( vb ) == size_type( gsl_DIMENSION_OF( b ) ) ); + EXPECT( size( wa ) == size_type( gsl_DIMENSION_OF( a ) ) ); + EXPECT( size( wb ) == size_type( gsl_DIMENSION_OF( b ) ) ); + EXPECT( size( z ) == size_type( 0 ) ); + EXPECT( size( y ) == size_type( 0 ) ); +} + +CASE( "ssize(): Allows to obtain the number of elements in span via ssize(span), signed" ) +{ + int a[] = { 1, 2, 3, }; + int b[] = { 1, 2, 3, 4, 5, }; + + span<int> z; + span<int> va( a ); + span<int> vb( b ); + span<int, 0> y; + span<int, 3> wa( a ); + span<int, 5> wb( b ); + + EXPECT( ssize( va ) == difference_type( gsl_DIMENSION_OF( a ) ) ); + EXPECT( ssize( vb ) == difference_type( gsl_DIMENSION_OF( b ) ) ); + EXPECT( ssize( wa ) == difference_type( gsl_DIMENSION_OF( a ) ) ); + EXPECT( ssize( wb ) == difference_type( gsl_DIMENSION_OF( b ) ) ); + EXPECT( ssize( z ) == difference_type( 0 ) ); + EXPECT( ssize( y ) == difference_type( 0 ) ); +} + +#if ! gsl_FEATURE_TO_STD( MAKE_SPAN ) + +CASE( "make_span(): unavailable (gsl_FEATURE_MAKE_SPAN=0)" ) +{ + EXPECT( !!"(avoid warning)" ); // suppress: unused parameter 'lest_env' [-Wunused-parameter] +} + +#else + +CASE( "make_span(): (gsl_FEATURE_MAKE_SPAN=1)" ) +{ + EXPECT( !!"(avoid warning)" ); // suppress: unused parameter 'lest_env' [-Wunused-parameter] +} + +CASE( "make_span(): Allows to build from two pointers" ) +{ + int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, }; + + span<int> v = make_span( arr, arr + gsl_DIMENSION_OF( arr ) ); + + EXPECT( std::equal( v.begin(), v.end(), arr ) ); +} + +CASE( "make_span(): Allows to build from two const pointers" ) +{ + const int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, }; + + span<const int> v = make_span( arr, arr + gsl_DIMENSION_OF( arr ) ); + + EXPECT( std::equal( v.begin(), v.end(), arr ) ); +} + +CASE( "make_span(): Allows to build from a non-null pointer and a size" ) +{ + int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, }; + + span<int> v = make_span( arr, gsl_DIMENSION_OF( arr ) ); + + EXPECT( std::equal( v.begin(), v.end(), arr ) ); +} + +CASE( "make_span(): Allows to build from a non-null const pointer and a size" ) +{ + const int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, }; + + span<const int> v = make_span( arr, gsl_DIMENSION_OF( arr ) ); + + EXPECT( std::equal( v.begin(), v.end(), arr ) ); +} + +CASE( "make_span(): Allows to build from a C-array" ) +{ + int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, }; + + span<int> v = make_span( arr ); + span<int, 9> w = make_span( arr ); + + EXPECT( std::equal( v.begin(), v.end(), arr ) ); + EXPECT( std::equal( w.begin(), w.end(), arr ) ); +} + +CASE( "make_span(): Allows to build from a const C-array" ) +{ + const int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, }; + + span<const int> v = make_span( arr ); + span<const int, 9> w = make_span( arr ); + + EXPECT( std::equal( v.begin(), v.end(), arr ) ); + EXPECT( std::equal( w.begin(), w.end(), arr ) ); +} + +CASE( "make_span(): Allows building from a std::initializer_list<> (C++11)" ) +{ +#if gsl_HAVE( INITIALIZER_LIST ) && ( gsl_HAVE( CONSTRAINED_SPAN_CONTAINER_CTOR ) || gsl_HAVE( UNCONSTRAINED_SPAN_CONTAINER_CTOR ) ) + auto il = { 1, 2, 3, 4, 5, 6, 7, 8, 9, }; + + span<int const> v = make_span( il ); + + EXPECT( std::equal( v.begin(), v.end(), il.begin() ) ); +#else + EXPECT( !!"std::initializer_list<> is not available (no C++11)" ); +#endif +} + +CASE( "make_span(): Allows to build from a std::array<> (C++11)" ) +{ +#if gsl_HAVE( ARRAY ) + std::array<int,9> arr = {{ 1, 2, 3, 4, 5, 6, 7, 8, 9, }}; + + span<int> v = make_span( arr ); + span<int, 9> w = make_span( arr ); + + EXPECT( std::equal( v.begin(), v.end(), arr.begin() ) ); + EXPECT( std::equal( w.begin(), w.end(), arr.begin() ) ); +#else + EXPECT( !!"std::array<> is not available (no C++11)" ); +#endif +} + +CASE( "make_span(): Allows to build from a const std::array<> (C++11)" ) +{ +#if gsl_HAVE( ARRAY ) + const std::array<int,9> arr = {{ 1, 2, 3, 4, 5, 6, 7, 8, 9, }}; + + span<const int> v = make_span( arr ); + span<const int, 9> w = make_span( arr ); + + EXPECT( std::equal( v.begin(), v.end(), arr.begin() ) ); + EXPECT( std::equal( w.begin(), w.end(), arr.begin() ) ); +#else + EXPECT( !!"std::array<> is not available (no C++11)" ); +#endif +} + +CASE( "make_span(): Allows to build from a container (std::vector<>)" ) +{ + std::vector<int> vec = vector_iota(10); + span<int> v = make_span( vec ); + + EXPECT( std::equal( v.begin(), v.end(), vec.begin() ) ); +} + +CASE( "make_span(): Allows to build from a const container (std::vector<>)" ) +{ + const std::vector<int> vec = vector_iota(10); + span<const int> v = make_span( vec ); + + EXPECT( std::equal( v.begin(), v.end(), vec.begin() ) ); +} + +CASE( "make_span(): Allows to build from a temporary container (potentially dangerous)" ) +{ + std::vector<int> vec = vector_iota(10); + + EXPECT( std::equal( vec.begin(), vec.end(), make_span( vector_iota( 10 ) ).begin() ) ); +} + +CASE( "make_span(): Allows to tag-build from a container (std::vector<>)" ) +{ +#if gsl_FEATURE_TO_STD( WITH_CONTAINER ) + std::vector<int> vec = vector_iota(10); + span< int> v = make_span( with_container, vec ); + span<const int> w = make_span( with_container, vec ); + + EXPECT( std::equal( v.begin(), v.end(), vec.begin() ) ); + EXPECT( std::equal( w.begin(), w.end(), vec.begin() ) ); +#else + EXPECT( !!"with_container is not available (gsl_FEATURE_WITH_CONTAINER_TO_STD)" ); +#endif +} + +CASE( "make_span(): Allows to tag-build from a temporary container (potentially dangerous)" ) +{ +#if gsl_FEATURE_TO_STD( WITH_CONTAINER ) + std::vector<int> vec = vector_iota(10); + + EXPECT( std::equal( vec.begin(), vec.end(), make_span( with_container, vector_iota( 10 ) ).begin() ) ); +#else + EXPECT( !!"with_container is not available (gsl_FEATURE_WITH_CONTAINER_TO_STD)" ); +#endif +} + +#endif // gsl_FEATURE( MAKE_SPAN ) + +#if ! gsl_FEATURE( BYTE ) || ! gsl_FEATURE_TO_STD( BYTE_SPAN ) + +CASE( "byte_span(): unavailable (gsl_FEATURE_BYTE_SPAN=0)" ) +{ + EXPECT( !!"(avoid warning)" ); // suppress: unused parameter 'lest_env' [-Wunused-parameter] +} + +#else + +CASE( "byte_span() (gsl_FEATURE_BYTE_SPAN=1)" ) +{ + EXPECT( !!"(avoid warning)" ); // suppress: unused parameter 'lest_env' [-Wunused-parameter] +} + +# if gsl_COMPILER_MSVC_VERSION +# pragma warning( push ) +# pragma warning( disable : 4127 ) // conditional expression is constant +# endif + +CASE( "byte_span(): Allows to build a span of gsl_lite::byte from a single object" ) +{ +# if gsl_HAVE( ENUM_CLASS ) + int x = (std::numeric_limits<int>::max)(); + + span<gsl_lite::byte> spn = byte_span( x ); + + EXPECT( spn.size() == size_type( sizeof x ) ); + if ( sizeof x > 1 ) + { + if ( std20::endian::native == std20::endian::little ) + { + EXPECT( spn[0] == to_byte( 0xff ) ); + EXPECT( spn[sizeof x - 1] == to_byte( 0x7f ) ); + } + else if ( std20::endian::native == std20::endian::big ) + { + EXPECT( spn[sizeof x - 1] == to_byte( 0xff ) ); + EXPECT( spn[0] == to_byte( 0x7f ) ); + } + } +# endif // gsl_HAVE( ENUM_CLASS ) +} + +CASE( "byte_span(): Allows to build a span of const gsl_lite::byte from a single const object" ) +{ +# if gsl_HAVE( ENUM_CLASS ) + const int x = (std::numeric_limits<int>::max)(); + + span<const gsl_lite::byte> spn = byte_span( x ); + + EXPECT( spn.size() == size_type( sizeof x ) ); + if ( sizeof x > 1 ) + { + if ( std20::endian::native == std20::endian::little ) + { + EXPECT( spn[0] == to_byte( 0xff ) ); + EXPECT( spn[sizeof x - 1] == to_byte( 0x7f ) ); + } + else if ( std20::endian::native == std20::endian::big ) + { + EXPECT( spn[sizeof x - 1] == to_byte( 0xff ) ); + EXPECT( spn[0] == to_byte( 0x7f ) ); + } + } +# endif // gsl_HAVE( ENUM_CLASS ) +} + +# if gsl_COMPILER_MSVC_VERSION +# pragma warning( pop ) +# endif + +#endif // span_PROVIDE( BYTE_SPAN ) + + +// end of file diff --git a/thirdparty/gsl-lite/test/string_span.t.cpp b/thirdparty/gsl-lite/test/string_span.t.cpp new file mode 100644 index 000000000..0756e4139 --- /dev/null +++ b/thirdparty/gsl-lite/test/string_span.t.cpp @@ -0,0 +1,1461 @@ +// +// gsl-lite is based on GSL: Guidelines Support Library. +// For more information see https://github.com/gsl-lite/gsl-lite +// +// Copyright (c) 2015-2019 Martin Moene +// Copyright (c) 2019-2021 Moritz Beutel +// Copyright (c) 2015-2018 Microsoft Corporation. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "gsl-lite.t.hpp" + +#include <sstream> // std::ostringstream +#include <string.h> // strlen() + +#if gsl_HAVE( WCHAR ) +# include <wchar.h> // wcslen() +#endif + +using namespace gsl_lite; + +#if gsl_FEATURE( STRING_SPAN ) + +typedef string_span::index_type index_type; + +template< typename T > +inline std::vector<T> vector_iota( int n ) +{ + std::vector<T> result; + + for ( int i = 0; i < n; ++i ) + result.push_back( static_cast<T>( i ) ); + + return result; +} + +CASE( "string_span: Disallows construction of a string_span from a cstring_span (define gsl_CONFIG_CONFIRMS_COMPILATION_ERRORS)" ) +{ +# if gsl_CONFIG( CONFIRMS_COMPILATION_ERRORS ) + cstring_span sv = "hello"; + + string_span v2 = sv; +# endif +} + +CASE( "string_span: Disallows construction of a string_span from a const std::string (define gsl_CONFIG_CONFIRMS_COMPILATION_ERRORS)" ) +{ +# if gsl_CONFIG( CONFIRMS_COMPILATION_ERRORS ) + const std::string s = "hello, world"; + + string_span sv( s ); + + EXPECT( sv.length() == index_type( 5 ) ); + EXPECT( std::string( sv.data() ) == s ); +# endif +} + +CASE( "string_span: Allows to default-construct" ) +{ + string_span s; + + EXPECT( s.size() == index_type( 0 ) ); +} + +CASE( "string_span: Allows to construct from a nullptr (C++11)" ) +{ +# if gsl_HAVE( NULLPTR ) + string_span v( nullptr ); + cstring_span w( nullptr ); + + EXPECT( v.size() == index_type( 0 ) ); + EXPECT( w.size() == index_type( 0 ) ); +# else + EXPECT( !!"nullptr is not available (no C++11)" ); +# endif +} + +CASE( "string_span: Allows to construct a cstring_span from a const C-string" ) +{ + cstring_span sv = "hello"; + + EXPECT( sv.length() == index_type( 5 ) ); + EXPECT( std::string( sv.data() ) == "hello" ); +} + +CASE( "string_span: Allows to construct a string_span from a non-const C-string and size" ) +{ + char s[] = "hello"; + + string_span sv( s, strlen( s ) ); + + EXPECT( sv.length() == index_type( 5 ) ); + EXPECT( std::string( sv.data() ) == s ); +} + +CASE( "string_span: Allows to construct a string_span from a non-const C-string begin and end pointer" ) +{ + char s[] = "hello"; + + string_span sv( s, s + strlen( s ) ); + + EXPECT( sv.length() == index_type( 5 ) ); + EXPECT( std::string( sv.data() ) == s ); +} + +CASE( "string_span: Allows to construct a string_span from a non-const C-array" ) +{ + char s[] = { 'w', 'o', 'r', 'l', 'd', '\0' }; + + string_span sv( s ); + + EXPECT( sv.length() == index_type( 5 ) ); + EXPECT( std::string( sv.data() ) == "world" ); +} + +CASE( "string_span: Allows to construct a string_span from a non-const std::string" ) +{ + std::string s = "hello, world"; + + string_span sv( s ); + + EXPECT( sv.length() == 12u ); + EXPECT( std::string( sv.data() ) == s ); +} + +CASE( "string_span: Allows to construct a string_span from a non-const std::array (C++11)" ) +{ +# if gsl_HAVE( ARRAY ) + std::array<char,6> arr = {{ 'w', 'o', 'r', 'l', 'd', '\0' }}; + + string_span sv( arr ); + + EXPECT( sv.length() == index_type( 5 ) ); + EXPECT( std::equal( sv.begin(), sv.end(), arr.begin() ) ); +# else + EXPECT( !!"std::array<> is not available (no C++11)" ); +# endif +} + +CASE( "string_span: Allows to construct a string_span from a non-const container (std::vector)" ) +{ + +# if gsl_HAVE( INITIALIZER_LIST ) + std::vector<char> vec = { 'w', 'o', 'r', 'l', 'd', '\0' }; +# else + std::vector<char> vec( 6, 'w' ); +# endif +# if gsl_HAVE( CONSTRAINED_SPAN_CONTAINER_CTOR ) || gsl_HAVE( UNCONSTRAINED_SPAN_CONTAINER_CTOR ) + string_span sv( vec ); + + EXPECT( sv.length() == index_type( 6 ) ); + EXPECT( std::equal( sv.begin(), sv.end(), vec.begin() ) ); +# else + EXPECT( !!"(un)constrained construction from container is not available" ); +# endif +} + +CASE( "string_span: Allows to construct a string_span from a non-const container, via a tag (std::vector)" ) +{ +# if gsl_FEATURE_TO_STD( WITH_CONTAINER ) + std::vector<char> vec = vector_iota<char>( 10 ); + + string_span sv( with_container, vec ); + + EXPECT( sv.length() == index_type( 10 ) ); + EXPECT( std::equal( sv.begin(), sv.end(), vec.begin() ) ); +# else + EXPECT( !!"with_container is not available (gsl_FEATURE_WITH_CONTAINER_TO_STD)" ); +# endif +} + +CASE( "string_span: Allows to construct a cstring_span from a non-const C-string and size" ) +{ + char s[] = "hello"; + + cstring_span sv( s, strlen( s ) ); + + EXPECT( sv.length() == index_type( 5 ) ); + EXPECT( std::string( sv.data() ) == s ); +} + +CASE( "string_span: Allows to construct a cstring_span from a non-const C-string begin and end pointer" ) +{ + char s[] = "hello"; + + cstring_span sv( s, s + strlen( s ) ); + + EXPECT( sv.length() == index_type( 5 ) ); + EXPECT( std::string( sv.data() ) == s ); +} + +CASE( "string_span: Allows to construct a cstring_span from a non-const C-array" ) +{ + char s[] = { 'w', 'o', 'r', 'l', 'd', '\0' }; + + cstring_span sv( s ); + +# if gsl_HAVE( CONSTRAINED_SPAN_CONTAINER_CTOR ) || gsl_COMPILER_MSVC_VERSION + EXPECT( sv.length() == index_type( 5 ) ); +# elif gsl_HAVE( UNCONSTRAINED_SPAN_CONTAINER_CTOR ) + EXPECT( !!"Warning: Unconstrained span container constructor enabled: terminating '\0' included in span" ); + EXPECT( sv.length() == index_type( 6 ) ); +# else + EXPECT( sv.length() == index_type( 5 ) ); +# endif + EXPECT( std::string( sv.data() ) == "world" ); +} + +CASE( "string_span: Allows to construct a cstring_span from a non-const std::string" ) +{ +# if gsl_HAVE( CONSTRAINED_SPAN_CONTAINER_CTOR ) || gsl_HAVE( UNCONSTRAINED_SPAN_CONTAINER_CTOR ) + std::string s = "hello, world"; + + cstring_span sv( s ); + + EXPECT( sv.length() == 12u ); + EXPECT( std::string( sv.data() ) == s ); +# else + EXPECT( !!"(un)constrained construction from container is not available" ); +# endif +} + +CASE( "string_span: Allows to construct a cstring_span from a non-const std::array (C++11)" ) +{ +# if gsl_HAVE( ARRAY ) + std::array<char,6> arr = {{ 'w', 'o', 'r', 'l', 'd', '\0' }}; + + cstring_span sv( arr ); + + EXPECT( sv.length() == index_type( 5 ) ); + EXPECT( std::equal( sv.begin(), sv.end(), arr.begin() ) ); +# else + EXPECT( !!"std::array<> is not available (no C++11)" ); +# endif +} + +CASE( "string_span: Allows to construct a cstring_span from a non-const container (std::vector)" ) +{ +# if gsl_HAVE( INITIALIZER_LIST ) + std::vector<char> vec = { 'w', 'o', 'r', 'l', 'd', '\0' }; +# else + std::vector<char> vec( 6, 'w' ); +# endif +# if gsl_HAVE( CONSTRAINED_SPAN_CONTAINER_CTOR ) || gsl_HAVE( UNCONSTRAINED_SPAN_CONTAINER_CTOR ) + cstring_span sv( vec ); + + EXPECT( sv.length() == index_type( 6 ) ); + EXPECT( std::equal( sv.begin(), sv.end(), vec.begin() ) ); +# else + EXPECT( !!"(un)constrained construction from container is not available" ); +# endif +} + +CASE( "string_span: Allows to construct a cstring_span from a non-const container, via a tag (std::vector)" ) +{ +# if gsl_FEATURE_TO_STD( WITH_CONTAINER ) + std::vector<char> vec = vector_iota<char>( 9 ); + + cstring_span sv( with_container, vec ); + + EXPECT( sv.length() == index_type( 9 ) ); + EXPECT( std::equal( sv.begin(), sv.end(), vec.begin() ) ); +# else + EXPECT( !!"with_container is not available (gsl_FEATURE_WITH_CONTAINER_TO_STD)" ); +# endif +} + +CASE( "string_span: Allows to construct a cstring_span from a const C-string and size" ) +{ + const char s[] = "hello"; + + cstring_span sv( s, strlen( s ) ); + + EXPECT( sv.length() == index_type( 5 ) ); + EXPECT( std::string( sv.data() ) == s ); +} + +CASE( "string_span: Allows to construct a cstring_span from a non-const C-string begin and end pointer" ) +{ + const char s[] = "hello"; + + cstring_span sv( s, s + strlen( s ) ); + + EXPECT( sv.length() == index_type( 5 ) ); + EXPECT( std::string( sv.data() ) == s ); +} + +CASE( "string_span: Allows to construct a cstring_span from a const C-array" ) +{ + const char s[] = { 'w', 'o', 'r', 'l', 'd', '\0' }; + + cstring_span sv( s ); + + EXPECT( sv.length() == index_type( 5 ) ); + EXPECT( std::string( sv.data() ) == "world" ); +} + +CASE( "string_span: Allows to construct a cstring_span from a const std::string" ) +{ +# if gsl_HAVE( CONSTRAINED_SPAN_CONTAINER_CTOR ) || gsl_HAVE( UNCONSTRAINED_SPAN_CONTAINER_CTOR ) + const std::string s = "hello, world"; + + cstring_span sv( s ); + + EXPECT( sv.length() == 12u ); + EXPECT( std::string( sv.data() ) == s ); +# else + EXPECT( !!"(un)constrained construction from container is not available" ); +# endif +} + +CASE( "string_span: Allows to construct a cstring_span from a const std::array (C++11)" ) +{ +# if gsl_HAVE( ARRAY ) + const std::array<char,6> arr = {{ 'w', 'o', 'r', 'l', 'd', '\0' }}; + + cstring_span sv( arr ); + + EXPECT( sv.length() == index_type( 5 ) ); + EXPECT( std::equal( sv.begin(), sv.end(), arr.begin() ) ); +# else + EXPECT( !!"std::array<> is not available (no C++11)" ); +# endif +} + +CASE( "string_span: Allows to construct a cstring_span from a const container (std::vector)" ) +{ +# if gsl_HAVE( INITIALIZER_LIST ) + const std::vector<char> vec = { 'w', 'o', 'r', 'l', 'd', '\0' }; +# else + const std::vector<char> vec( 6, 'w' ); +# endif +# if gsl_HAVE( CONSTRAINED_SPAN_CONTAINER_CTOR ) || gsl_HAVE( UNCONSTRAINED_SPAN_CONTAINER_CTOR ) + cstring_span sv( vec ); + + EXPECT( sv.length() == index_type( 6 ) ); + EXPECT( std::equal( sv.begin(), sv.end(), vec.begin() ) ); +# else + EXPECT( !!"(un)constrained construction from container is not available" ); +# endif +} + +CASE( "string_span: Allows to construct a cstring_span from a const container, via a tag (std::vector)" ) +{ +# if gsl_FEATURE_TO_STD( WITH_CONTAINER ) + const std::vector<char> vec = vector_iota<char>( 9 ); + + cstring_span sv( with_container, vec ); + + EXPECT( sv.length() == index_type( 9 ) ); + EXPECT( std::equal( sv.begin(), sv.end(), vec.begin() ) ); +# else + EXPECT( !!"with_container is not available (gsl_FEATURE_WITH_CONTAINER_TO_STD)" ); +# endif +} + +# if gsl_HAVE( WCHAR ) + +CASE( "string_span: Allows to construct a wstring_span from a non-const C-string and size" ) +{ + wchar_t s[] = L"hello"; + + wstring_span sv( s, wcslen( s ) ); + + EXPECT( std::wstring( sv.data() ) == std::wstring( s ) ); +} + +CASE( "string_span: Allows to construct a wstring_span from a non-const C-string begin and end pointer" ) +{ + wchar_t s[] = L"hello"; + + wstring_span sv( s, s + wcslen( s ) ); + + EXPECT( sv.length() == index_type( 5 ) ); + EXPECT( std::wstring( sv.data() ) == s ); +} + +CASE( "string_span: Allows to construct a wstring_span from a non-const C-array" ) +{ + wchar_t s[] = { L'w', L'o', L'r', L'l', L'd', L'\0' }; + + wstring_span sv( s ); + + EXPECT( sv.length() == index_type( 5 ) ); + EXPECT( std::wstring( sv.data() ) == std::wstring( s ) ); +} + +CASE( "string_span: Allows to construct a wstring_span from a non-const std::wstring" ) +{ + std::wstring s = L"hello, world"; + + wstring_span sv( s ); + + EXPECT( sv.length() == 12u ); + EXPECT( std::wstring( sv.data() ) == s ); +} + +CASE( "string_span: Allows to construct a wstring_span from a non-const std::array (C++11)" ) +{ +# if gsl_HAVE( ARRAY ) + std::array<wchar_t,6> arr = {{ 'w', 'o', 'r', 'l', 'd', '\0' }}; + + wstring_span sv( arr ); + + EXPECT( sv.length() == index_type( 5 ) ); + EXPECT( std::equal( sv.begin(), sv.end(), arr.begin() ) ); +# else + EXPECT( !!"std::array<> is not available (no C++11)" ); +# endif +} + +CASE( "string_span: Allows to construct a wstring_span from a non-const container (std::vector)" ) +{ +# if gsl_HAVE( INITIALIZER_LIST ) + std::vector<wchar_t> vec = { L'w', L'o', L'r', L'l', L'd', L'\0' }; +# else + std::vector<wchar_t> vec( 6, 'w' ); +# endif +# if gsl_HAVE( CONSTRAINED_SPAN_CONTAINER_CTOR ) || gsl_HAVE( UNCONSTRAINED_SPAN_CONTAINER_CTOR ) + wstring_span sv( vec ); + + EXPECT( sv.length() == index_type( 6 ) ); + EXPECT( std::equal( sv.begin(), sv.end(), vec.begin() ) ); +# else + EXPECT( !!"(un)constrained construction from container is not available" ); +# endif +} + +CASE( "string_span: Allows to construct a wstring_span from a non-const container, via a tag (std::vector)" ) +{ +# if gsl_FEATURE_TO_STD( WITH_CONTAINER ) + std::vector<wchar_t> vec = vector_iota<wchar_t>( 9 ); + + wstring_span sv( with_container, vec ); + + EXPECT( sv.length() == index_type( 9 ) ); + EXPECT( std::equal( sv.begin(), sv.end(), vec.begin() ) ); +# else + EXPECT( !!"with_container is not available (gsl_FEATURE_WITH_CONTAINER_TO_STD)" ); +# endif +} + +CASE( "string_span: Allows to construct a cwstring_span from a non-const C-string and size" ) +{ + wchar_t s[] = L"hello"; + + cwstring_span sv( s, wcslen( s ) ); + + EXPECT( sv.length() == index_type( 5 ) ); + EXPECT( std::wstring( sv.data() ) == std::wstring( s ) ); +} + +CASE( "string_span: Allows to construct a cwstring_span from a non-const C-string begin and end pointer" ) +{ + wchar_t s[] = L"hello"; + + cwstring_span sv( s, s + wcslen( s ) ); + + EXPECT( sv.length() == index_type( 5 ) ); + EXPECT( std::wstring( sv.data() ) == s ); +} + +CASE( "string_span: Allows to construct a cwstring_span from a non-const C-array" ) +{ + wchar_t s[] = { L'w', L'o', L'r', L'l', L'd', L'\0' }; + + cwstring_span sv( s ); + +# if gsl_HAVE( CONSTRAINED_SPAN_CONTAINER_CTOR ) || gsl_COMPILER_MSVC_VERSION + EXPECT( sv.length() == index_type( 5 ) ); +# elif gsl_HAVE( UNCONSTRAINED_SPAN_CONTAINER_CTOR ) + EXPECT( !!"Warning: Unconstrained span container constructor enabled: terminating '\0' included in span" ); + EXPECT( sv.length() == index_type( 6 ) ); +# else + EXPECT( sv.length() == index_type( 5 ) ); +# endif + EXPECT( std::wstring( sv.data() ) == std::wstring( s ) ); +} + +CASE( "string_span: Allows to construct a cwstring_span from a non-const std::wstring" ) +{ + std::wstring s = L"hello, world"; + + cwstring_span sv( s ); + + EXPECT( sv.length() == 12u ); + EXPECT( std::wstring( sv.data() ) == s ); +} + +CASE( "string_span: Allows to construct a cwstring_span from a non-const std::array (C++11)" ) +{ +# if gsl_HAVE( ARRAY ) + std::array<wchar_t,6> arr = {{ 'w', 'o', 'r', 'l', 'd', '\0' }}; + + cwstring_span sv( arr ); + + EXPECT( sv.length() == index_type( 5 ) ); + EXPECT( std::equal( sv.begin(), sv.end(), arr.begin() ) ); +# else + EXPECT( !!"std::array<> is not available (no C++11)" ); +# endif +} + +CASE( "string_span: Allows to construct a cwstring_span from a non-const container (std::vector)" ) +{ +# if gsl_HAVE( INITIALIZER_LIST ) + std::vector<wchar_t> vec = { L'w', L'o', L'r', L'l', L'd', L'\0' }; +# else + std::vector<wchar_t> vec( 6, 'w' ); +# endif +# if gsl_HAVE( CONSTRAINED_SPAN_CONTAINER_CTOR ) || gsl_HAVE( UNCONSTRAINED_SPAN_CONTAINER_CTOR ) + cwstring_span sv( vec ); + + EXPECT( sv.length() == index_type( 6 ) ); + EXPECT( std::equal( sv.begin(), sv.end(), vec.begin() ) ); +# else + EXPECT( !!"(un)constrained construction from container is not available" ); +# endif +} + +CASE( "string_span: Allows to construct a cwstring_span from a non-const container, via a tag (std::vector)" ) +{ +# if gsl_FEATURE_TO_STD( WITH_CONTAINER ) + std::vector<wchar_t> vec = vector_iota<wchar_t>( 9 ); + + cwstring_span sv( with_container, vec ); + + EXPECT( sv.length() == index_type( 9 ) ); + EXPECT( std::equal( sv.begin(), sv.end(), vec.begin() ) ); +# else + EXPECT( !!"with_container is not available (gsl_FEATURE_WITH_CONTAINER_TO_STD)" ); +# endif +} + +CASE( "string_span: Allows to construct a cwstring_span from a const C-string and size" ) +{ + const wchar_t s[] = L"hello"; + + cwstring_span sv( s, wcslen( s ) ); + + EXPECT( sv.length() == index_type( 5 ) ); + EXPECT( std::wstring( sv.data() ) == std::wstring( s ) ); +} + +CASE( "string_span: Allows to construct a cwstring_span from a const C-string begin and end pointer" ) +{ + const wchar_t s[] = L"hello"; + + cwstring_span sv( s, s + wcslen( s ) ); + + EXPECT( sv.length() == index_type( 5 ) ); + EXPECT( std::wstring( sv.data() ) == s ); +} + +CASE( "string_span: Allows to construct a cwstring_span from a const C-array" ) +{ + const wchar_t s[] = { L'w', L'o', L'r', L'l', L'd', L'\0' }; + + cwstring_span sv( s ); + + EXPECT( sv.length() == index_type( 5 ) ); + EXPECT( std::wstring( sv.data() ) == std::wstring( s ) ); +} + +CASE( "string_span: Allows to construct a cwstring_span from a const std::wstring" ) +{ + const std::wstring s = L"hello, world"; + + cwstring_span sv( s ); + + EXPECT( sv.length() == 12u ); + EXPECT( std::wstring( sv.data() ) == s ); +} + +CASE( "string_span: Allows to construct a cwstring_span from a const std::array (C++11)" ) +{ +# if gsl_HAVE( ARRAY ) + const std::array<wchar_t,6> arr = {{ 'w', 'o', 'r', 'l', 'd', '\0' }}; + + cwstring_span sv( arr ); + + EXPECT( sv.length() == index_type( 5 ) ); + EXPECT( std::equal( sv.begin(), sv.end(), arr.begin() ) ); +# else + EXPECT( !!"std::array<> is not available (no C++11)" ); +# endif +} + +CASE( "string_span: Allows to construct a cwstring_span from a const container (std::vector)" ) +{ +# if gsl_HAVE( INITIALIZER_LIST ) + const std::vector<wchar_t> vec = { L'w', L'o', L'r', L'l', L'd', L'\0' }; +# else + const std::vector<wchar_t> vec( 6, 'w' ); +# endif +# if gsl_HAVE( CONSTRAINED_SPAN_CONTAINER_CTOR ) || gsl_HAVE( UNCONSTRAINED_SPAN_CONTAINER_CTOR ) + cwstring_span sv( vec ); + + EXPECT( sv.length() == index_type( 6 ) ); + EXPECT( std::equal( sv.begin(), sv.end(), vec.begin() ) ); +# else + EXPECT( !!"(un)constrained construction from container is not available" ); +# endif +} + +CASE( "string_span: Allows to construct a cwstring_span from a const container, via a tag (std::vector)" ) +{ +# if gsl_FEATURE_TO_STD( WITH_CONTAINER ) + const std::vector<wchar_t> vec = vector_iota<wchar_t>( 9 ); + + cwstring_span sv( with_container, vec ); + + EXPECT( sv.length() == index_type( 9 ) ); + EXPECT( std::equal( sv.begin(), sv.end(), vec.begin() ) ); +# else + EXPECT( !!"with_container is not available (gsl_FEATURE_WITH_CONTAINER_TO_STD)" ); +# endif +} + +# endif // gsl_HAVE( WCHAR ) + +CASE( "string_span: Allows to copy-construct from another span of the same type" ) +{ + cstring_span a = "hello"; + + cstring_span b( a ); + + EXPECT( a.length() == b.length() ); + EXPECT( std::equal( a.begin(), a.end(), b.begin() ) ); +} + +CASE( "string_span: Allows to copy-construct from another span of a compatible type" ) +{ + char hello[] = "hello"; + string_span a = hello; + + cstring_span b( a ); + + EXPECT( a.length() == b.length() ); + EXPECT( std::equal( a.begin(), a.end(), b.begin() ) ); +} + +CASE( "string_span: Allows to move-construct from another span of the same type (C++11)" ) +{ +# if gsl_STDLIB_CPP11_OR_GREATER + char hello[] = "hello"; + + string_span a(( string_span( hello ) )); + + EXPECT( a.length() == index_type( strlen( hello ) ) ); + EXPECT( std::equal( a.begin(), a.end(), hello ) ); +# else + EXPECT( !!"move-semantics are not available (no C++11)" ); +# endif +} + +CASE( "string_span: Allows to copy-assign from another span of the same type" ) +{ + char hello[] = "hello"; + string_span a = hello; + string_span b; + + b = a; + + EXPECT( a.length() == b.length() ); + EXPECT( std::equal( a.begin(), a.end(), b.begin() ) ); +} + +CASE( "string_span: Allows to move-assign from another span of the same type (C++11)" ) +{ +# if gsl_STDLIB_CPP11_OR_GREATER + char hello[] = "hello"; + string_span a; + + a = string_span( hello ); + + EXPECT( a.length() == index_type( strlen( hello ) ) ); + EXPECT( std::equal( a.begin(), a.end(), hello ) ); +# else + EXPECT( !!"move-semantics are not available (no C++11)" ); +# endif +} + +CASE( "string_span: Allows to create a sub span of the first n elements" ) +{ + char hello[] = "hello"; + string_span a( hello ); + index_type count = 2; + + string_span s = a.first( count ); + + EXPECT( s.size() == count ); + EXPECT( std::equal( s.begin(), s.end(), hello ) ); +} + +CASE( "string_span: Allows to create a sub span of the last n elements" ) +{ + char hello[] = "hello"; + string_span a( hello ); + index_type count = 2; + + string_span s = a.last( count ); + + EXPECT( s.size() == count ); + EXPECT( std::equal( s.begin(), s.end(), hello + strlen(hello) - count ) ); +} + +CASE( "string_span: Allows to create a sub span starting at a given offset" ) +{ + char hello[] = "hello"; + string_span a( hello ); + index_type offset = 1; + + string_span s = a.subspan( offset ); + + EXPECT( s.size() == index_type( strlen(hello) - offset ) ); + EXPECT( std::equal( s.begin(), s.end(), hello + offset ) ); +} + +CASE( "string_span: Allows to create a sub span starting at a given offset with a given length" ) +{ + char hello[] = "hello"; + string_span a( hello ); + index_type offset = 1; + index_type length = 1; + + string_span s = a.subspan( offset, length ); + + EXPECT( s.size() == length ); + EXPECT( std::equal( s.begin(), s.end(), hello + offset ) ); +} + +CASE( "string_span: Allows to create an empty sub span at full offset" ) +{ + char hello[] = "hello"; + string_span a( hello ); + index_type offset = strlen( hello ); + + string_span s = a.subspan( offset ); + + EXPECT( s.empty() ); +} + +CASE( "string_span: Allows to create an empty sub span at full offset with zero length" ) +{ + char hello[] = "hello"; + string_span a( hello ); + index_type offset = strlen( hello ); + index_type length = 0; + + string_span s = a.subspan( offset, length ); + + EXPECT( s.empty() ); +} + +CASE( "string_span: Allows forward iteration" ) +{ + char hello[] = "hello"; + string_span a( hello ); + + for ( string_span::iterator pos = a.begin(); pos != a.end(); ++pos ) + { + index_type i = narrow_failfast<index_type>( std::distance( a.begin(), pos ) ); + EXPECT( *pos == a[i] ); + } +} + +CASE( "string_span: Allows const forward iteration" ) +{ + char hello[] = "hello"; + string_span a( hello ); + + for ( string_span::const_iterator pos = a.begin(); pos != a.end(); ++pos ) + { + index_type i = narrow_failfast<index_type>( std::distance( a.cbegin(), pos ) ); + EXPECT( *pos == a[i] ); + } +} + +CASE( "string_span: Allows reverse iteration" ) +{ + char hello[] = "hello"; + string_span a( hello ); + + for ( string_span::reverse_iterator pos = a.rbegin(); pos != a.rend(); ++pos ) + { + index_type dist = narrow_failfast<index_type>( std::distance( a.rbegin(), pos ) ); + EXPECT( *pos == a[ a.size() - 1 - dist ] ); + } +} + +CASE( "string_span: Allows const reverse iteration" ) +{ + char hello[] = "hello"; + string_span a( hello ); + + for ( string_span::const_reverse_iterator pos = a.crbegin(); pos != a.crend(); ++pos ) + { + index_type dist = narrow_failfast<index_type>( std::distance( a.crbegin(), pos ) ); + EXPECT( *pos == a[ a.size() - 1 - dist ] ); + } +} + +CASE( "string_span: Allows to observe an element via array indexing" ) +{ + char hello[] = "hello"; + string_span a( hello ); + + for ( index_type i = 0; i < a.size(); ++i ) + { + EXPECT( a[i] == hello[i] ); + EXPECT( &a[i] == &hello[i] ); + } +} + +CASE( "string_span: Allows to observe an element via front() and back()" ) +{ + char hello[] = "hello"; + string_span a( hello ); + + EXPECT( a.front() == hello[0] ); + EXPECT( &a.front() == &hello[0] ); + EXPECT( a.back() == hello[4] ); + EXPECT( &a.back() == &hello[4] ); +} + +CASE( "string_span: Allows to observe an element via data()" ) +{ + char hello[] = "hello"; + string_span a( hello ); + + EXPECT( *a.data() == *a.begin() ); + EXPECT( a.data() == &*a.begin() ); + + for ( index_type i = 0; i < a.size(); ++i ) + { + EXPECT( a.data()[i] == hello[i] ); + EXPECT( a.data()[i] == hello[i] ); + } +} + +CASE( "string_span: Allows to change an element via array indexing" ) +{ + char hello[] = "hello"; + string_span a( hello ); + + a[1] = '7'; + + EXPECT( hello[1] == '7' ); +} + +CASE( "string_span: Allows to change an element via front() and back()" ) +{ + char hello[] = "hello"; + string_span a( hello ); + + a.front() = '1'; + a.back() = '2'; + + EXPECT( hello[0] == '1' ); + EXPECT( hello[4] == '2' ); +} + +# if 0 +CASE( "string_span: Allows to change an element via at()" ) +{ + char hello[] = "hello"; + string_span a( hello ); + + a.at(1) = '7'; + + EXPECT( hello[1] == '7' ); +} +# endif + +CASE( "string_span: Allows to change an element via data()" ) +{ + char hello[] = "hello"; + string_span a( hello ); + + *a.data() = '7'; + + EXPECT( hello[0] == '7' ); +} + +CASE( "string_span: Allows to compare a string_span with another string_span" ) +{ + char s[] = "hello"; + char t[] = "world"; + + string_span sv( s, strlen( s ) ); + string_span tv( t, strlen( s ) ); + + EXPECT( sv.length() == index_type( 5 ) ); + EXPECT( tv.length() == index_type( 5 ) ); + + EXPECT( sv == sv ); + EXPECT( sv != tv ); + EXPECT( sv <= sv ); + EXPECT( sv <= tv ); + EXPECT( sv < tv ); + EXPECT( tv >= tv ); + EXPECT( tv >= sv ); + EXPECT( tv > sv ); +} + +CASE( "string_span: Allows to compare empty spans as equal (questionable)" "[.]" ) +{ + string_span a, b; + + EXPECT( a == b ); +} + +CASE( "string_span: Allows to compare empty span to non-empty span" ) +{ + char s[] = "hello"; + string_span a, b( s, strlen( s ) ); + + EXPECT( a != b ); + EXPECT( b != a ); +} + +CASE( "string_span: Allows to compare a string_span with a cstring_span" ) +{ +# if gsl_CONFIG( ALLOWS_NONSTRICT_SPAN_COMPARISON ) + char s[] = "hello"; + + string_span sv( s, strlen( s ) ); + cstring_span csv( s, strlen( s ) ); + + EXPECT( sv == csv ); +# else + EXPECT( !!"string_span: cannot compare different types (gsl_CONFIG_ALLOWS_NONSTRICT_SPAN_COMPARISON=0)" ); +# endif +} + +CASE( "string_span: Allows to compare with types convertible to string_span" ) +{ +# if gsl_CONFIG( ALLOWS_NONSTRICT_SPAN_COMPARISON ) + + char const * phello = "hello"; + char const ahello[] = "hello"; + std::string shello = "hello"; + cstring_span a = phello; + + EXPECT( a == phello ); + EXPECT( a == ahello ); + EXPECT( a == shello ); + EXPECT( a <= phello ); + EXPECT( a <= ahello ); + EXPECT( a <= shello ); + EXPECT( a >= phello ); + EXPECT( a >= ahello ); + EXPECT( a >= shello ); + + EXPECT_NOT( a != phello ); + EXPECT_NOT( a != ahello ); + EXPECT_NOT( a != shello ); + EXPECT_NOT( a < phello ); + EXPECT_NOT( a < ahello ); + EXPECT_NOT( a < shello ); + EXPECT_NOT( a > phello ); + EXPECT_NOT( a > ahello ); + EXPECT_NOT( a > shello ); + +# if gsl_HAVE( OWNER_TEMPLATE ) + EXPECT( phello == a ); + EXPECT( ahello == a ); + EXPECT( shello == a ); + EXPECT( phello <= a ); + EXPECT( ahello <= a ); + EXPECT( shello <= a ); + EXPECT( phello >= a ); + EXPECT( ahello >= a ); + EXPECT( shello >= a ); + + EXPECT_NOT( phello != a ); + EXPECT_NOT( ahello != a ); + EXPECT_NOT( shello != a ); + EXPECT_NOT( phello < a ); + EXPECT_NOT( ahello < a ); + EXPECT_NOT( shello < a ); + EXPECT_NOT( phello > a ); + EXPECT_NOT( ahello > a ); + EXPECT_NOT( shello > a ); +# endif + +# if gsl_HAVE( ARRAY ) + std::array<char,6> world = {{ 'w', 'o', 'r', 'l', 'd', '\0' }}; + cstring_span b = world; + + EXPECT( b == world ); +# if gsl_HAVE( OWNER_TEMPLATE ) + EXPECT( world == b ); +# endif +# endif +# else + EXPECT( !!"string_span: cannot compare different types (gsl_CONFIG_ALLOWS_NONSTRICT_SPAN_COMPARISON=0)" ); +# endif +} + +CASE( "string_span: Allows to test for empty span via empty(), empty case" ) +{ + string_span sz; + + EXPECT( sz.empty() ); +} + +CASE( "string_span: Allows to test for empty span via empty(), non-empty case" ) +{ + cstring_span s = "hello"; + + EXPECT_NOT( s.empty() ); +} + +CASE( "string_span: Allows to obtain the number of elements via length()" ) +{ + char a[] = "hello"; + char b[] = "world"; + string_span sz; + string_span sa = a; + string_span sb = b; + + EXPECT( sz.length() == index_type( 0 ) ); + EXPECT( sa.length() == index_type( strlen( a ) ) ); + EXPECT( sb.length() == index_type( strlen( b ) ) ); +} + +CASE( "string_span: Allows to obtain the number of elements via size()" ) +{ + char a[] = "hello"; + char b[] = "world"; + string_span sz; + string_span sa = a; + string_span sb = b; + + EXPECT( sz.size() == index_type( 0 ) ); + EXPECT( sa.size() == index_type( strlen( a ) ) ); + EXPECT( sb.size() == index_type( strlen( b ) ) ); +} + +# if gsl_HAVE( WCHAR ) + +CASE( "string_span: Allows to obtain the number of bytes via length_bytes()" ) +{ + wchar_t a[] = L"hello"; + wchar_t b[] = L"world"; + wstring_span sz; + wstring_span sa = a; + wstring_span sb = b; + + EXPECT( sz.length_bytes() == index_type( 0 ) ); + EXPECT( sa.length_bytes() == index_type( sizeof(wchar_t) * wcslen( a ) ) ); + EXPECT( sb.length_bytes() == index_type( sizeof(wchar_t) * wcslen( b ) ) ); +} + +CASE( "string_span: Allows to obtain the number of bytes via size_bytes()" ) +{ + wchar_t a[] = L"hello"; + wchar_t b[] = L"world"; + wstring_span sz; + wstring_span sa = a; + wstring_span sb = b; + + EXPECT( sz.size_bytes() == index_type( 0 ) ); + EXPECT( sa.size_bytes() == index_type( sizeof(wchar_t) * wcslen( a ) ) ); + EXPECT( sb.size_bytes() == index_type( sizeof(wchar_t) * wcslen( b ) ) ); +} + +# endif // gsl_HAVE( WCHAR ) + +CASE( "string_span: Allows to view the elements as read-only bytes" ) +{ + char const * hello = "hello"; + cstring_span s( hello); + + span<const gsl_lite::byte> b = as_bytes( s ); + + EXPECT( b[0] == to_byte( hello[0] ) ); + EXPECT( b[1] == to_byte( hello[1] ) ); + EXPECT( b[2] == to_byte( hello[2] ) ); + EXPECT( b[3] == to_byte( hello[3] ) ); + EXPECT( b[4] == to_byte( hello[4] ) ); +} + +//------------------------------------------------------------------------ +// zstring_span + +CASE( "zstring_span: Terminates construction of a zstring_span from an empty span" ) +{ + span<char> s; + EXPECT_THROWS( (void) zstring_span( s ) ); +} + +CASE( "zstring_span: Allows to construct a zstring_span from a zero-terminated empty string (via span)" ) +{ + char zero[] = ""; + + zstring_span zsv( make_span( zero, 1 ) ); + + EXPECT_NOT( zsv.empty() ); + EXPECT( zsv.ensure_z().size() == 0u ); + EXPECT( zsv.as_string_span().size() == 0u ); + EXPECT( std::string( zsv.as_string_span().data() ) == "" ); +} + +CASE( "zstring_span: Allows to construct a zstring_span from a zero-terminated non-empty string (via span)" ) +{ + char hello[] = "hello, world"; + const index_type len = std::string(hello).length(); + + zstring_span zsv( make_span( hello, len + 1 ) ); + + EXPECT_NOT( zsv.empty() ); + EXPECT( zsv.ensure_z().size() == len ); + EXPECT( zsv.as_string_span().size() == len ); + EXPECT( std::string( zsv.as_string_span().data() ) == hello ); +} + +CASE( "zstring_span: Terminates construction of a zstring_span from a non-zero-terminated string (via span)" ) +{ + struct F + { + static void blow() + { + char hello[] = "hello, worldxxx"; + const index_type len = std::string(hello).length(); + + zstring_span zsv( make_span( hello, len ) ); + } + }; + + EXPECT_THROWS( F::blow() ); +} + +# if gsl_HAVE( WCHAR ) + +CASE( "zstring_span: Terminates construction of a wzstring_span from an empty span" ) +{ + span<wchar_t> s; + EXPECT_THROWS( (void) wzstring_span( s ) ); +} + +CASE( "zstring_span: Allows to construct a wzstring_span from a zero-terminated empty string (via span)" ) +{ + wchar_t zero[] = L""; + + wzstring_span wzsv( make_span( zero, 1 ) ); + + EXPECT_NOT( wzsv.empty() ); + EXPECT( wzsv.ensure_z().size() == 0u ); + EXPECT( wzsv.as_string_span().size() == 0u ); + EXPECT( std::wstring( wzsv.as_string_span().data() ) == L"" ); +} + +CASE( "zstring_span: Allows to construct a wzstring_span from a zero-terminated non-empty string (via span)" ) +{ + wchar_t hello[] = L"hello, world"; + const index_type len = std::wstring(hello).length(); + + wzstring_span wzsv( make_span( hello, len + 1 ) ); + + EXPECT_NOT( wzsv.empty() ); + EXPECT( wzsv.ensure_z().size() == len ); + EXPECT( wzsv.as_string_span().size() == len ); +// EXPECT( std::wstring( wzsv.as_string_span().data() ) == hello ); +} + +CASE( "zstring_span: Terminates construction of a wzstring_span from a non-zero-terminated string (via span)" ) +{ + struct F + { + static void blow() + { + wchar_t hello[] = L"hello, worldxxx"; + const index_type len = std::wstring(hello).length(); + + wzstring_span wzsv( make_span( hello, len ) ); + } + }; + + EXPECT_THROWS( F::blow() ); +} + +# endif // gsl_HAVE( WCHAR ) + +CASE( "zstring_span: Allows to use a zstring_span with a legacy API via member assume_z()" ) +{ + char hello[] = "hello, world"; + const std::string::size_type len = std::string(hello).length(); + + zstring_span zsv( make_span( hello, len + 1 ) ); + czstring czs( zsv.assume_z() ); + + EXPECT( strlen( czs ) == len ); + EXPECT( *(czs + len ) == '\0'); +} + +# if gsl_HAVE( WCHAR ) + +CASE( "zstring_span: Allows to use a wzstring_span with a legacy API via member assume_z()" ) +{ + wchar_t hello[] = L"hello, world"; + const index_type len = std::wstring(hello).length(); + + wzstring_span wzsv( make_span( hello, len + 1 ) ); + cwzstring cwzs( wzsv.assume_z() ); + + EXPECT( wcslen( cwzs ) == len ); + EXPECT( *(cwzs + len ) == '\0'); +} + +# endif // gsl_HAVE( WCHAR ) + +//------------------------------------------------------------------------ +// global functions: + +CASE( "to_string(): Allows to explicitly convert from string_span to std::string" ) +{ + char s[] = "hello"; + + string_span sv( s, strlen( s ) ); + + EXPECT( sv.length() == index_type( 5 ) ); + EXPECT( to_string( sv ) == s ); +} + +CASE( "to_string(): Allows to explicitly convert from cstring_span to std::string" ) +{ + const char s[] = "hello"; + + cstring_span sv( s, strlen( s ) ); + + EXPECT( sv.length() == index_type( 5 ) ); + EXPECT( to_string( sv ) == s ); +} + +# if gsl_HAVE( WCHAR ) + +CASE( "to_string(): Allows to explicitly convert from wstring_span to std::wstring" ) +{ + wchar_t s[] = L"hello"; + + wstring_span sv( s, wcslen( s ) ); + + std::wstring ws( to_string( wstring_span( s, wcslen( s ) ) ) ); + + EXPECT( sv.length() == index_type( 5 ) ); + EXPECT( std::equal( ws.begin(), ws.end(), s ) ); +} + +CASE( "to_string(): Allows to explicitly convert from cwstring_span to std::wstring" ) +{ + wchar_t s[] = L"hello"; + + std::wstring ws( to_string( cwstring_span( s, wcslen( s ) ) ) ); + + EXPECT( ws.length() == 5u ); + EXPECT( std::equal( ws.begin(), ws.end(), s ) ); +} + +# endif // gsl_HAVE( WCHAR ) + +CASE( "ensure_z(): Disallows to build a string_span from a const C-string" ) +{ +# if gsl_CONFIG( CONFIRMS_COMPILATION_ERRORS ) + const char s[] = "hello"; + + string_span sv = ensure_z( s ); + + EXPECT( sv.length() == 5u ); + EXPECT( std::string( sv.data() ) == s ); +# endif +} + +# if gsl_HAVE( WCHAR ) +CASE( "ensure_z(): Disallows to build a wstring_span from a const wide C-string" ) +{ +# if gsl_CONFIG( CONFIRMS_COMPILATION_ERRORS ) + const wchar_t s[] = L"hello"; + + wstring_span sv = ensure_z( s ); + + EXPECT( sv.length() == 5 ); + EXPECT( std::wstring( sv.data() ) == std::wstring( s ) ); +# endif +} +# endif // gsl_HAVE( WCHAR ) + +CASE( "ensure_z(): Allows to build a string_span from a non-const C-string" ) +{ + char s[] = "hello"; + +# if gsl_COMPILER_MSVC_VERSION != 60 + string_span sv = ensure_z( s ); +# else + string_span sv = ensure_z( &s[0] ); +# endif + EXPECT( sv.length() == index_type( 5 ) ); + EXPECT( std::string( sv.data() ) == s ); +} + +CASE( "ensure_z(): Allows to build a cstring_span from a non-const C-string" ) +{ + char s[] = "hello"; + +# if gsl_COMPILER_MSVC_VERSION != 60 + cstring_span sv = ensure_z( s ); +# else + cstring_span sv = ensure_z( &s[0] ); +# endif + + EXPECT( sv.length() == index_type( 5 ) ); + EXPECT( std::string( sv.data() ) == s ); +} + +CASE( "ensure_z(): Allows to build a cstring_span from a const C-string" ) +{ + const char s[] = "hello"; + +# if gsl_COMPILER_MSVC_VERSION != 60 + cstring_span sv = ensure_z( s ); +# else + cstring_span sv = ensure_z( &s[0] ); +# endif + + EXPECT( sv.length() == index_type( 5 ) ); + EXPECT( std::string( sv.data() ) == s ); +} + +# if gsl_HAVE( WCHAR ) + +CASE( "ensure_z(): Allows to build a wstring_span from a non-const wide C-string" ) +{ + wchar_t s[] = L"hello"; + +# if gsl_COMPILER_MSVC_VERSION != 60 + wstring_span sv = ensure_z( s ); +# else + wstring_span sv = ensure_z( &s[0] ); +# endif + + EXPECT( sv.length() == index_type( 5 ) ); + EXPECT( std::wstring( sv.data() ) == std::wstring( s ) ); +} + +CASE( "ensure_z(): Allows to build a cwstring_span from a non-const wide C-string" ) +{ + wchar_t s[] = L"hello"; + +# if gsl_COMPILER_MSVC_VERSION != 60 + cwstring_span sv = ensure_z( s ); +# else + cwstring_span sv = ensure_z( &s[0] ); +# endif + + EXPECT( sv.length() == index_type( 5 ) ); + EXPECT( std::wstring( sv.data() ) == std::wstring( s ) ); +} + +CASE( "ensure_z(): Allows to build a cwstring_span from a const wide C-string" ) +{ + const wchar_t s[] = L"hello"; + +# if gsl_COMPILER_MSVC_VERSION != 60 + cwstring_span sv = ensure_z( s ); +# else + cwstring_span sv = ensure_z( &s[0] ); +# endif + + EXPECT( sv.length() == index_type( 5 ) ); + EXPECT( std::wstring( sv.data() ) == std::wstring( s ) ); +} + +# endif // gsl_HAVE( WCHAR ) + +CASE( "ensure_z(): Allows to specify ultimate location of the sentinel and ensure its presence" ) +{ + const char * s = "hello"; // not: s[] + + EXPECT_THROWS( (void) ensure_z( s, index_type( 3 ) ) ); +} + +CASE ( "operator<<: Allows printing a string_span to an output stream" ) +{ + std::ostringstream oss; + char s[] = "hello"; + string_span sv = ensure_z( s ); + + oss << sv << '\n' + << std::right << std::setw(10) << sv << '\n' + << sv << '\n' + << std::setfill('.') << std::left << std::setw(10) << sv; + + EXPECT( oss.str() == "hello\n hello\nhello\nhello....." ); +} + +CASE ( "operator<<: Allows printing a cstring_span to an output stream" ) +{ + std::ostringstream oss; + char s[] = "hello"; + cstring_span sv = ensure_z( s ); + + oss << sv << '\n' + << std::right << std::setw(10) << sv << '\n' + << sv << '\n' + << std::setfill('.') << std::left << std::setw(10) << sv; + + EXPECT( oss.str() == "hello\n hello\nhello\nhello....." ); +} + +# if gsl_HAVE( WCHAR ) + +CASE ( "operator<<: Allows printing a wstring_span to an output stream" ) +{ + std::wostringstream oss; + wchar_t s[] = L"hello"; + wstring_span sv = ensure_z( s ); + + oss << sv << '\n' + << std::right << std::setw(10) << sv << '\n' + << sv << '\n' + << std::setfill(L'.') << std::left << std::setw(10) << sv; + + EXPECT( oss.str() == L"hello\n hello\nhello\nhello....." ); +} + +CASE ( "operator<<: Allows printing a cwstring_span to an output stream" ) +{ + std::wostringstream oss; + wchar_t s[] = L"hello"; + cwstring_span sv = ensure_z( s ); + + oss << sv << '\n' + << std::right << std::setw(10) << sv << '\n' + << sv << '\n' + << std::setfill(L'.') << std::left << std::setw(10) << sv; + + EXPECT( oss.str() == L"hello\n hello\nhello\nhello....." ); +} + +# endif // gsl_HAVE( WCHAR ) + +# if ! gsl_HAVE( WCHAR ) + +CASE( "string_span: wstring_span and cwstring_span not available (wchar_t not available)" ) +{ + EXPECT( true ); +} +# endif // gsl_HAVE( WCHAR ) +#endif // gsl_FEATURE( STRING_SPAN ) + +// end of file diff --git a/thirdparty/gsl-lite/test/util.t.cpp b/thirdparty/gsl-lite/test/util.t.cpp new file mode 100644 index 000000000..0c99efd32 --- /dev/null +++ b/thirdparty/gsl-lite/test/util.t.cpp @@ -0,0 +1,337 @@ +// +// gsl-lite is based on GSL: Guidelines Support Library. +// For more information see https://github.com/gsl-lite/gsl-lite +// +// Copyright (c) 2015-2019 Martin Moene +// Copyright (c) 2019-2021 Moritz Beutel +// Copyright (c) 2015-2018 Microsoft Corporation. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "gsl-lite.t.hpp" +#include <cstddef> +#include <complex> +#include <functional> + +#if gsl_STDLIB_CPP11_OR_GREATER +# include <limits> +# include <cstdint> +#endif // gsl_STDLIB_CPP11_OR_GREATER + +#define gsl_STDLIB_CPP11_OR_GREATER_WRT_FINAL ( gsl_STDLIB_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VERSION >= 110 ) + +using namespace gsl_lite; + +CASE( "finally: Allows to run lambda on leaving scope" ) +{ +#if gsl_STDLIB_CPP11_OR_GREATER_WRT_FINAL + struct F { static void incr( int & i ) { i += 1; } }; + + int i = 0; + { + auto _ = finally( [&]() { F::incr( i ); } ); + EXPECT( i == 0 ); + } + EXPECT( i == 1 ); +#else + EXPECT( !!"lambda is not available (no C++11)" ); +#endif +} + +CASE( "finally: Allows to run function (bind) on leaving scope" ) +{ +#if gsl_STDLIB_CPP11_OR_GREATER_WRT_FINAL + struct F { static void incr( int & i ) { i += 1; } }; + + int i = 0; + { + auto _ = finally( std::bind( &F::incr, std::ref( i ) ) ); + EXPECT( i == 0 ); + } + EXPECT( i == 1 ); +#else + EXPECT( !!"auto and std::ref perhaps not available (no C++11)" ); +#endif +} + +namespace{ int g_i = 0; } + +CASE( "finally: Allows to run function (pointer) on leaving scope" ) +{ + struct F { static void incr() { g_i += 1; } }; + +#if gsl_STDLIB_CPP11_OR_GREATER_WRT_FINAL + + g_i = 0; + { + auto _ = finally( &F::incr ); + EXPECT( g_i == 0 ); + } + EXPECT( g_i == 1 ); +#endif +} + +CASE( "on_return: Allows to perform action on leaving scope without exception (gsl_FEATURE_EXPERIMENTAL_RETURN_GUARD)" ) +{ +#if gsl_HAVE( EXCEPTIONS ) +# if gsl_FEATURE( EXPERIMENTAL_RETURN_GUARD ) +# if gsl_STDLIB_CPP11_OR_GREATER_WRT_FINAL + struct F { + static void incr() { g_i += 1; } + static void pass() { try { auto _ = on_return( &F::incr ); /*throw std::exception();*/ } catch (...) {} } + static void fail() { try { auto _ = on_return( &F::incr ); throw std::exception(); } catch (...) {} } + }; + struct G { + ~G() { F::pass(); } + }; + { g_i = 0; F::pass(); EXPECT( g_i == 1 ); } + { g_i = 0; F::fail(); EXPECT( g_i == 0 ); } + { g_i = 0; try { G g; throw std::exception(); } catch (...) {}; EXPECT( g_i == 1 ); } +# endif +# else + EXPECT( !!"on_return not available (no gsl_FEATURE_EXPERIMENTAL_RETURN_GUARD)" ); +# endif +#endif // gsl_HAVE( EXCEPTIONS ) +} + +CASE( "on_error: Allows to perform action on leaving scope via an exception (gsl_FEATURE_EXPERIMENTAL_RETURN_GUARD)" ) +{ +#if gsl_HAVE( EXCEPTIONS ) +# if gsl_FEATURE( EXPERIMENTAL_RETURN_GUARD ) +# if gsl_STDLIB_CPP11_OR_GREATER_WRT_FINAL + struct F { + static void incr() { g_i += 1; } + static void pass() { try { auto _ = on_error( &F::incr ); /*throw std::exception();*/ } catch (...) {} } + static void fail() { try { auto _ = on_error( &F::incr ); throw std::exception(); } catch (...) {} } + }; + struct G { + ~G() { F::pass(); } + }; + { g_i = 0; F::pass(); EXPECT( g_i == 0 ); } + { g_i = 0; F::fail(); EXPECT( g_i == 1 ); } + { g_i = 0; try { G g; throw std::exception(); } catch (...) {}; EXPECT( g_i == 0 ); } +# endif +# else + EXPECT( !!"on_error not available (no gsl_FEATURE_EXPERIMENTAL_RETURN_GUARD)" ); +# endif +#endif // gsl_HAVE( EXCEPTIONS ) +} + +CASE( "narrow_cast<>: Allows narrowing without value loss" ) +{ + EXPECT( narrow_cast<char>( 120 ) == 120 ); +} + +CASE( "narrow_cast<>: Allows narrowing with value loss" ) +{ + EXPECT( narrow_cast<unsigned char>( 300 ) == 44 ); +} + +#if gsl_STDLIB_CPP11_OR_GREATER +const std::uint8_t u8 = std::uint8_t((std::numeric_limits< std::uint8_t>::max)() - 1); +const std::uint16_t u16 = std::uint16_t((std::numeric_limits<std::uint16_t>::max)() - 1); +const std::int8_t i8n = std::int8_t((std::numeric_limits< std::int8_t>::min)() + 1); +const std::int16_t i16n = std::int16_t((std::numeric_limits< std::int16_t>::min)() + 1); +const std::int8_t i8p = std::int8_t((std::numeric_limits< std::int8_t>::max)() - 1); +const std::int16_t i16p = std::int16_t((std::numeric_limits< std::int16_t>::max)() - 1); +#endif // gsl_CPP11_OR_GREATER + +CASE( "narrow<>(): Allows narrowing without value loss" ) +{ +#if gsl_HAVE( EXCEPTIONS ) + EXPECT( narrow<char>( 120 ) == 120 ); + +# if gsl_STDLIB_CPP11_OR_GREATER + std::uint8_t lu8; + std::uint16_t lu16; + std::int8_t li8; + std::int16_t li16; + + // uint <-> uint + EXPECT_NO_THROW((lu16 = narrow<std::uint16_t>( std::uint8_t( u8)))); EXPECT(lu16 == u8); + EXPECT_NO_THROW(( lu8 = narrow< std::uint8_t>( std::uint8_t( u8)))); EXPECT( lu8 == u8); + EXPECT_NO_THROW(( lu8 = narrow< std::uint8_t>(std::uint16_t( u8)))); EXPECT( lu8 == u8); + + // int <-> int + EXPECT_NO_THROW((li16 = narrow< std::int16_t>( std::int8_t(i8n)))); EXPECT(li16 == i8n); + EXPECT_NO_THROW((li16 = narrow< std::int16_t>( std::int8_t(i8p)))); EXPECT(li16 == i8p); + EXPECT_NO_THROW(( li8 = narrow< std::int8_t>( std::int8_t(i8n)))); EXPECT( li8 == i8n); + EXPECT_NO_THROW(( li8 = narrow< std::int8_t>( std::int8_t(i8p)))); EXPECT( li8 == i8p); + EXPECT_NO_THROW(( li8 = narrow< std::int8_t>( std::int16_t(i8n)))); EXPECT( li8 == i8n); + EXPECT_NO_THROW(( li8 = narrow< std::int8_t>( std::int16_t(i8p)))); EXPECT( li8 == i8p); + + // uint <-> int + EXPECT_NO_THROW((lu16 = narrow<std::uint16_t>( std::int8_t(i8p)))); EXPECT(lu16 == i8p); + EXPECT_NO_THROW((li16 = narrow< std::int16_t>( std::uint8_t(i8p)))); EXPECT(li16 == i8p); + EXPECT_NO_THROW(( lu8 = narrow< std::uint8_t>( std::int8_t(i8p)))); EXPECT( lu8 == i8p); + EXPECT_NO_THROW(( li8 = narrow< std::int8_t>( std::uint8_t(i8p)))); EXPECT( li8 == i8p); + EXPECT_NO_THROW(( lu8 = narrow< std::uint8_t>( std::int16_t(i8p)))); EXPECT( lu8 == i8p); + EXPECT_NO_THROW(( li8 = narrow< std::int8_t>(std::uint16_t(i8p)))); EXPECT( li8 == i8p); +# endif // gsl_STDLIB_CPP11_OR_GREATER +#endif // gsl_HAVE( EXCEPTIONS ) +} + +CASE( "narrow<>(): Allows narrowing unordered type without precision loss" ) +{ +#if gsl_HAVE( EXCEPTIONS ) && gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) + std::complex<float> cf; + EXPECT_NO_THROW( cf = narrow<std::complex<float>>( std::complex<double>( 4, 2 ) ) ); + EXPECT( narrow<std::complex<float>>( std::complex<double>( 4, 2 ) ) == std::complex<float>( 4, 2 ) ); +#endif // gsl_HAVE( EXCEPTIONS ) && gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) +} + +CASE( "narrow<>(): Throws when narrowing with value loss" ) +{ +#if gsl_HAVE( EXCEPTIONS ) && gsl_CONFIG( NARROW_THROWS_ON_TRUNCATION ) + EXPECT_THROWS_AS( (void) narrow<char>( 300 ), narrowing_error ); + +# if gsl_STDLIB_CPP11_OR_GREATER + // uint <-> uint + EXPECT_THROWS_AS( (void) narrow< std::uint8_t>( std::uint16_t( u16) ), narrowing_error ); + + // int <-> int + EXPECT_THROWS_AS( (void) narrow< std::int8_t>( std::int16_t(i16n) ), narrowing_error ); + EXPECT_THROWS_AS( (void) narrow< std::int8_t>( std::int16_t(i16p) ), narrowing_error ); + + // uint <-> int + EXPECT_THROWS_AS( (void) narrow< std::int8_t>( std::uint8_t( u8 ) ), narrowing_error ); + EXPECT_THROWS_AS( (void) narrow< std::uint8_t>( std::int16_t(i16p) ), narrowing_error ); + EXPECT_THROWS_AS( (void) narrow< std::int8_t>( std::uint16_t( u8 ) ), narrowing_error ); + EXPECT_THROWS_AS( (void) narrow< std::int8_t>( std::uint16_t(u16 ) ), narrowing_error ); +# endif // gsl_STDLIB_CPP11_OR_GREATER +#endif // gsl_HAVE( EXCEPTIONS ) && gsl_CONFIG( NARROW_THROWS_ON_TRUNCATION ) +} + +CASE( "narrow<>(): Throws when narrowing with sign loss" ) +{ +#if gsl_HAVE( EXCEPTIONS ) && gsl_CONFIG( NARROW_THROWS_ON_TRUNCATION ) + EXPECT_THROWS_AS( (void) narrow<unsigned>( -42 ), narrowing_error ); + +# if gsl_STDLIB_CPP11_OR_GREATER + // uint <-> int + EXPECT_THROWS_AS( (void) narrow<std::uint16_t>( std::int8_t( i8n) ), narrowing_error ); + EXPECT_THROWS_AS( (void) narrow< std::uint8_t>( std::int8_t( i8n) ), narrowing_error ); + EXPECT_THROWS_AS( (void) narrow< std::uint8_t>( std::int16_t( i8n) ), narrowing_error ); + EXPECT_THROWS_AS( (void) narrow< std::uint8_t>( std::int16_t(i16n) ), narrowing_error ); +# endif // gsl_STDLIB_CPP11_OR_GREATER +#endif // gsl_HAVE( EXCEPTIONS ) && gsl_CONFIG( NARROW_THROWS_ON_TRUNCATION ) +} + +CASE( "narrow<>(): Throws when narrowing unordered type with precision loss" ) +{ +#if gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) && gsl_HAVE( EXCEPTIONS ) && gsl_CONFIG( NARROW_THROWS_ON_TRUNCATION ) + EXPECT_THROWS_AS( (void) narrow<std::complex<float>>( std::complex<double>( 4.2 ) ), narrowing_error ); +#endif // gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) && gsl_HAVE( EXCEPTIONS ) && gsl_CONFIG( NARROW_THROWS_ON_TRUNCATION ) +} + +CASE( "narrow_failfast<>(): Allows narrowing without value loss" ) +{ + EXPECT( narrow_failfast<char>( 120 ) == 120 ); + +#if gsl_STDLIB_CPP11_OR_GREATER + std::uint8_t lu8; + std::uint16_t lu16; + std::int8_t li8; + std::int16_t li16; + + // uint <-> uint + EXPECT_NO_THROW((lu16 = narrow_failfast<std::uint16_t>( std::uint8_t( u8)))); EXPECT(lu16 == u8); + EXPECT_NO_THROW(( lu8 = narrow_failfast< std::uint8_t>( std::uint8_t( u8)))); EXPECT( lu8 == u8); + EXPECT_NO_THROW(( lu8 = narrow_failfast< std::uint8_t>(std::uint16_t( u8)))); EXPECT( lu8 == u8); + + // int <-> int + EXPECT_NO_THROW((li16 = narrow_failfast< std::int16_t>( std::int8_t(i8n)))); EXPECT(li16 == i8n); + EXPECT_NO_THROW((li16 = narrow_failfast< std::int16_t>( std::int8_t(i8p)))); EXPECT(li16 == i8p); + EXPECT_NO_THROW(( li8 = narrow_failfast< std::int8_t>( std::int8_t(i8n)))); EXPECT( li8 == i8n); + EXPECT_NO_THROW(( li8 = narrow_failfast< std::int8_t>( std::int8_t(i8p)))); EXPECT( li8 == i8p); + EXPECT_NO_THROW(( li8 = narrow_failfast< std::int8_t>( std::int16_t(i8n)))); EXPECT( li8 == i8n); + EXPECT_NO_THROW(( li8 = narrow_failfast< std::int8_t>( std::int16_t(i8p)))); EXPECT( li8 == i8p); + + // uint <-> int + EXPECT_NO_THROW((lu16 = narrow_failfast<std::uint16_t>( std::int8_t(i8p)))); EXPECT(lu16 == i8p); + EXPECT_NO_THROW((li16 = narrow_failfast< std::int16_t>( std::uint8_t(i8p)))); EXPECT(li16 == i8p); + EXPECT_NO_THROW(( lu8 = narrow_failfast< std::uint8_t>( std::int8_t(i8p)))); EXPECT( lu8 == i8p); + EXPECT_NO_THROW(( li8 = narrow_failfast< std::int8_t>( std::uint8_t(i8p)))); EXPECT( li8 == i8p); + EXPECT_NO_THROW(( lu8 = narrow_failfast< std::uint8_t>( std::int16_t(i8p)))); EXPECT( lu8 == i8p); + EXPECT_NO_THROW(( li8 = narrow_failfast< std::int8_t>(std::uint16_t(i8p)))); EXPECT( li8 == i8p); +#endif // gsl_STDLIB_CPP11_OR_GREATER +} + +CASE( "narrow_failfast<>(): Allows narrowing unordered type without precision loss" ) +{ +#if gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) + std::complex<float> cf; + EXPECT_NO_THROW( cf = narrow_failfast<std::complex<float>>( std::complex<double>( 4, 2 ) ) ); + EXPECT( narrow_failfast<std::complex<float>>( std::complex<double>( 4, 2 ) ) == std::complex<float>( 4, 2 ) ); +#endif // gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) +} + +CASE( "narrow_failfast<>(): Fails when narrowing with value loss" ) +{ + EXPECT_THROWS_AS( (void) narrow_failfast<char>( 300 ), fail_fast ); + +#if gsl_STDLIB_CPP11_OR_GREATER + // uint <-> uint + EXPECT_THROWS_AS( (void) narrow_failfast< std::uint8_t>( std::uint16_t( u16) ), fail_fast ); + + // int <-> int + EXPECT_THROWS_AS( (void) narrow_failfast< std::int8_t>( std::int16_t(i16n) ), fail_fast ); + EXPECT_THROWS_AS( (void) narrow_failfast< std::int8_t>( std::int16_t(i16p) ), fail_fast ); + + // uint <-> int + EXPECT_THROWS_AS( (void) narrow_failfast< std::int8_t>( std::uint8_t( u8 ) ), fail_fast ); + EXPECT_THROWS_AS( (void) narrow_failfast< std::uint8_t>( std::int16_t(i16p) ), fail_fast ); + EXPECT_THROWS_AS( (void) narrow_failfast< std::int8_t>( std::uint16_t( u8 ) ), fail_fast ); + EXPECT_THROWS_AS( (void) narrow_failfast< std::int8_t>( std::uint16_t(u16 ) ), fail_fast ); +#endif // gsl_STDLIB_CPP11_OR_GREATER +} + +CASE( "narrow_failfast<>(): Fails when narrowing with sign loss" ) +{ + EXPECT_THROWS_AS( (void) narrow_failfast<unsigned>( -42 ), fail_fast ); + +#if gsl_STDLIB_CPP11_OR_GREATER + // uint <-> int + EXPECT_THROWS_AS( (void) narrow_failfast<std::uint16_t>( std::int8_t( i8n) ), fail_fast ); + EXPECT_THROWS_AS( (void) narrow_failfast< std::uint8_t>( std::int8_t( i8n) ), fail_fast ); + EXPECT_THROWS_AS( (void) narrow_failfast< std::uint8_t>( std::int16_t( i8n) ), fail_fast ); + EXPECT_THROWS_AS( (void) narrow_failfast< std::uint8_t>( std::int16_t(i16n) ), fail_fast ); +#endif // gsl_STDLIB_CPP11_OR_GREATER +} + +CASE( "narrow_failfast<>(): Fails when narrowing unordered type with precision loss" ) +{ +#if gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) + EXPECT_THROWS_AS( (void) narrow_failfast<std::complex<float>>( std::complex<double>( 4.2 ) ), fail_fast ); +#endif // gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) +} + +#if gsl_CPP20_OR_GREATER && ( ! defined( _MSC_VER ) || gsl_COMPILER_MSVC_VERSION >= 1929 || gsl_COMPILER_CLANG_VERSION >= 1800 ) +struct Empty { }; +struct NoEmptyMember +{ + int nonEmpty; +}; +struct OneEmptyMember +{ + gsl_NO_UNIQUE_ADDRESS Empty empty; + int nonEmpty; +}; + +CASE( "gsl_NO_UNIQUE_ADDRESS: Class layout is compressed if attribute is used on empty members" ) +{ + EXPECT( sizeof( NoEmptyMember ) == sizeof( int ) ); + EXPECT( sizeof( OneEmptyMember ) == sizeof( NoEmptyMember ) ); + EXPECT( offsetof( OneEmptyMember, nonEmpty ) == offsetof( NoEmptyMember, nonEmpty ) ); +} +#endif // gsl_CPP20_OR_GREATER && ( ! defined( _MSC_VER ) || gsl_COMPILER_MSVC_VERSION >= 1929 || gsl_COMPILER_CLANG_VERSION >= 1800 ) + +// end of file diff --git a/thirdparty/xmake.lua b/thirdparty/xmake.lua index 30c6e39be..ae31dc784 100644 --- a/thirdparty/xmake.lua +++ b/thirdparty/xmake.lua @@ -168,3 +168,11 @@ target("ryml") else add_cxxflags("-Wno-unused-but-set-variable", "-Wno-undef") end + +target("gsl-lite") + set_kind("headeronly") + set_group("thirdparty") + -- TODO: should migrate to new include path `gsl-lite/gsl-lite.hpp` so this can be removed + add_defines("gsl_FEATURE_GSL_COMPATIBILITY_MODE=1", {public=true}) + add_headerfiles("gsl-lite/include/**.hpp") + add_includedirs("gsl-lite/include", {public=true}) @@ -12,7 +12,6 @@ add_requires("http_parser", {system = false}) add_requires( "vcpkg::curl", "vcpkg::eastl", - "vcpkg::gsl-lite", "vcpkg::zlib" ) |