diff --git a/CMakeLists.txt b/CMakeLists.txt index 347eb1d..57135b1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,6 +5,9 @@ project(GSL CXX) include(ExternalProject) find_package(Git) +# Use GNUInstallDirs to provide the right locations on all platforms +include(GNUInstallDirs) + # creates a library GSL which is an interface (header files only) add_library(GSL INTERFACE) @@ -54,15 +57,13 @@ target_compile_definitions(GSL INTERFACE # the SYSTEM keyword suppresses warnings for users of the library if(GSL_STANDALONE_PROJECT) target_include_directories(GSL INTERFACE - $ + $ + $ ) else() target_include_directories(GSL SYSTEM INTERFACE - $ + $ + $ ) endif() @@ -77,15 +78,23 @@ if (CMAKE_VERSION VERSION_GREATER 3.7.8) # add natvis file to the library so it will automatically be loaded into Visual Studio if(VS_ADD_NATIVE_VISUALIZERS) target_sources(GSL INTERFACE - ${CMAKE_CURRENT_SOURCE_DIR}/GSL.natvis + $ ) endif() endif() +install(TARGETS GSL EXPORT Microsoft.GSLConfig) install( DIRECTORY include/gsl - DESTINATION include + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} ) +# Make library importable by other projects +install(EXPORT Microsoft.GSLConfig NAMESPACE Microsoft.GSL:: DESTINATION share/Microsoft.GSL/cmake) +export(TARGETS GSL NAMESPACE Microsoft.GSL:: FILE Microsoft.GSLConfig.cmake) + +# Add Microsoft.GSL::GSL alias for GSL so that dependents can be agnostic about +# whether GSL was added via `add_subdirectory` or `find_package` +add_library(Microsoft.GSL::GSL ALIAS GSL) option(GSL_TEST "Generate tests." ${GSL_STANDALONE_PROJECT}) if (GSL_TEST) diff --git a/README.md b/README.md index 9115a28..3ea2f48 100644 --- a/README.md +++ b/README.md @@ -77,6 +77,18 @@ These steps assume the source code of this repository has been cloned into a dir All tests should pass - indicating your platform is fully supported and you are ready to use the GSL types! +## Building GSL - Using vcpkg + +You can download and install GSL using the [vcpkg](https://github.com/Microsoft/vcpkg) dependency manager: + + git clone https://github.com/Microsoft/vcpkg.git + cd vcpkg + ./bootstrap-vcpkg.sh + ./vcpkg integrate install + vcpkg install ms-gsl + +The GSL port in vcpkg is kept up to date by Microsoft team members and community contributors. If the version is out of date, please [create an issue or pull request](https://github.com/Microsoft/vcpkg) on the vcpkg repository. + ## Using the libraries As the types are entirely implemented inline in headers, there are no linking requirements. @@ -97,5 +109,14 @@ Include the library using: #include +## Usage in CMake + +The library provides a Config file for CMake, once installed it can be found via + + find_package(Microsoft.GSL CONFIG) + +Which, when successful, will add library target called `Microsoft.GSL::GSL` which you can use via the usual +`target_link_libraries` mechanism. + ## Debugging visualization support For Visual Studio users, the file [GSL.natvis](./GSL.natvis) in the root directory of the repository can be added to your project if you would like more helpful visualization of GSL types in the Visual Studio debugger than would be offered by default. diff --git a/include/gsl/gsl_algorithm b/include/gsl/gsl_algorithm index c2ba31f..6813b6c 100644 --- a/include/gsl/gsl_algorithm +++ b/include/gsl/gsl_algorithm @@ -37,8 +37,8 @@ namespace gsl { // Note: this will generate faster code than std::copy using span iterator in older msvc+stl // not necessary for msvc since VS2017 15.8 (_MSC_VER >= 1915) -template +template void copy(span src, span dest) { static_assert(std::is_assignable::value, diff --git a/include/gsl/gsl_assert b/include/gsl/gsl_assert index 7a9e8ad..96eaada 100644 --- a/include/gsl/gsl_assert +++ b/include/gsl/gsl_assert @@ -17,8 +17,27 @@ #ifndef GSL_CONTRACTS_H #define GSL_CONTRACTS_H +// +// Temporary until MSVC STL supports no-exceptions mode. +// Currently terminate is a no-op in this mode, so we add termination behavior back +// +#if defined(_MSC_VER) && (defined(_KERNEL_MODE) || (defined(_HAS_EXCEPTIONS) && !_HAS_EXCEPTIONS)) + +#define GSL_MSVC_USE_STL_NOEXCEPTION_WORKAROUND +#include +#define RANGE_CHECKS_FAILURE 0 + +#if defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Winvalid-noreturn" +#endif // defined(__clang__) + +#else // defined(_MSC_VER) && (defined(_KERNEL_MODE) || (defined(_HAS_EXCEPTIONS) && !_HAS_EXCEPTIONS)) + #include +#endif // defined(_MSC_VER) && (defined(_KERNEL_MODE) || (defined(_HAS_EXCEPTIONS) && !_HAS_EXCEPTIONS)) + // // make suppress attributes parse for some compilers // Hopefully temporary until suppression standardization occurs @@ -33,32 +52,18 @@ #endif // _MSC_VER #endif // __clang__ -// -// Temporary until MSVC STL supports no-exceptions mode. -// Currently terminate is a no-op in this mode, so we add termination behavior back -// -#if defined(_MSC_VER) && defined(_HAS_EXCEPTIONS) && !_HAS_EXCEPTIONS -#define GSL_MSVC_USE_STL_NOEXCEPTION_WORKAROUND -#include -#define RANGE_CHECKS_FAILURE 0 - -#if defined(__clang__) -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Winvalid-noreturn" -#endif - -#endif - #define GSL_STRINGIFY_DETAIL(x) #x #define GSL_STRINGIFY(x) GSL_STRINGIFY_DETAIL(x) #if defined(__clang__) || defined(__GNUC__) #define GSL_LIKELY(x) __builtin_expect(!!(x), 1) #define GSL_UNLIKELY(x) __builtin_expect(!!(x), 0) + #else + #define GSL_LIKELY(x) (!!(x)) #define GSL_UNLIKELY(x) (!!(x)) -#endif +#endif // defined(__clang__) || defined(__GNUC__) // // GSL_ASSUME(cond) @@ -85,9 +90,11 @@ namespace details { #if defined(GSL_MSVC_USE_STL_NOEXCEPTION_WORKAROUND) - typedef void (__cdecl *terminate_handler)(); + typedef void(__cdecl* terminate_handler)(); + // clang-format off GSL_SUPPRESS(f.6) // NO-FORMAT: attribute + // clang-format on [[noreturn]] inline void __cdecl default_terminate_handler() { __fastfail(RANGE_CHECKS_FAILURE); @@ -99,7 +106,7 @@ namespace details return handler; } -#endif +#endif // defined(GSL_MSVC_USE_STL_NOEXCEPTION_WORKAROUND) [[noreturn]] inline void terminate() noexcept { @@ -107,21 +114,12 @@ namespace details (*gsl::details::get_terminate_handler())(); #else std::terminate(); -#endif +#endif // defined(GSL_MSVC_USE_STL_NOEXCEPTION_WORKAROUND) } - template - [[deprecated("GSL no longer supports throwing for contract violations. Use gsl::details::terminate() instead.")]] - [[noreturn]] void throw_exception(Exception&&) noexcept - { - gsl::details::terminate(); - } - - } // namespace details } // namespace gsl - #define GSL_CONTRACT_CHECK(type, cond) \ (GSL_LIKELY(cond) ? static_cast(0) : gsl::details::terminate()) diff --git a/include/gsl/pointers b/include/gsl/pointers index 7afed1c..1caf294 100644 --- a/include/gsl/pointers +++ b/include/gsl/pointers @@ -88,7 +88,6 @@ public: { } - not_null(not_null&& other) = default; not_null(const not_null& other) = default; not_null& operator=(const not_null& other) = default; diff --git a/include/gsl/span b/include/gsl/span index 3daf16f..23c58c9 100644 --- a/include/gsl/span +++ b/include/gsl/span @@ -21,21 +21,18 @@ #include // for byte #include // for narrow_cast, narrow -#include // for lexicographical_compare #include // for array #include // for ptrdiff_t, size_t, nullptr_t #include // for reverse_iterator, distance, random_access_... -#include -#include #include // for enable_if_t, declval, is_convertible, inte... -#include -#include // for std::addressof #if defined(_MSC_VER) && !defined(__clang__) #pragma warning(push) // turn off some warnings that are noisy about our Expects statements #pragma warning(disable : 4127) // conditional expression is constant +#pragma warning( \ + disable : 4146) // unary minus operator applied to unsigned type, result still unsigned #pragma warning(disable : 4702) // unreachable code // Turn MSVC /analyze rules that generate too much noise. TODO: fix in the tool. @@ -58,7 +55,7 @@ // GCC 7 does not like the signed unsigned missmatch (size_t ptrdiff_t) // While there is a conversion from signed to unsigned, it happens at -// compiletime, so the compiler wouldn't have to warn indiscriminently, but +// 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 @@ -70,9 +67,9 @@ namespace gsl { // [views.constants], constants -constexpr const std::ptrdiff_t dynamic_extent = -1; +constexpr const std::size_t dynamic_extent = static_cast(-1); -template +template class span; // implementation details @@ -83,7 +80,7 @@ namespace details { }; - template + template struct is_span_oracle> : std::true_type { }; @@ -104,156 +101,189 @@ namespace details }; template - struct is_std_array : public is_std_array_oracle> + struct is_std_array : is_std_array_oracle> { }; - template + template struct is_allowed_extent_conversion - : public std::integral_constant + : std::integral_constant { }; template struct is_allowed_element_type_conversion - : public std::integral_constant::value> + : std::integral_constant::value> { }; - template + template class span_iterator { - using element_type_ = typename Span::element_type; - public: -#ifdef _MSC_VER - // Tell Microsoft standard library that span_iterators are checked. - using _Unchecked_type = typename Span::pointer; -#endif - using iterator_category = std::random_access_iterator_tag; - using value_type = std::remove_cv_t; - using difference_type = typename Span::index_type; + using value_type = std::remove_cv_t; + using difference_type = std::ptrdiff_t; + using pointer = Type*; + using reference = Type&; - using reference = std::conditional_t&; - using pointer = std::add_pointer_t; +#ifdef _MSC_VER + using _Unchecked_type = pointer; +#endif // _MSC_VER + constexpr span_iterator() = default; - span_iterator() = default; - - constexpr span_iterator(const Span* span, difference_type idx) noexcept - : span_(span), index_(idx) + constexpr span_iterator(pointer begin, pointer end, pointer current) + : begin_(begin), end_(end), current_(current) {} - friend span_iterator; - template * = nullptr> - constexpr span_iterator(const span_iterator& other) noexcept - : span_iterator(other.span_, other.index_) - {} - - GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute - constexpr reference operator*() const + constexpr operator span_iterator() const noexcept { - Expects(index_ != span_->size()); - return *(span_->data() + index_); + return {begin_, end_, current_}; } - constexpr pointer operator->() const + constexpr reference operator*() const noexcept { - Expects(index_ != span_->size()); - return span_->data() + index_; + Expects(begin_ && end_); + Expects(begin_ <= current_ && current_ < end_); + return *current_; } + constexpr pointer operator->() const noexcept + { + Expects(begin_ && end_); + Expects(begin_ <= current_ && current_ < end_); + return current_; + } constexpr span_iterator& operator++() noexcept { - Expects(0 <= index_ && index_ != span_->size()); - ++index_; + Expects(begin_ && current_ && end_); + Expects(current_ < end_); + ++current_; return *this; } constexpr span_iterator operator++(int) noexcept { - auto ret = *this; - ++(*this); + span_iterator ret = *this; + ++*this; return ret; } constexpr span_iterator& operator--() noexcept { - Expects(index_ != 0 && index_ <= span_->size()); - --index_; + Expects(begin_ && end_); + Expects(begin_ < current_); + --current_; return *this; } constexpr span_iterator operator--(int) noexcept { - auto ret = *this; - --(*this); + span_iterator ret = *this; + --*this; return ret; } - constexpr span_iterator operator+(difference_type n) const noexcept + constexpr span_iterator& operator+=(const difference_type n) noexcept { - auto ret = *this; - return ret += n; + if (n != 0) Expects(begin_ && current_ && end_); + if (n > 0) Expects(end_ - current_ >= n); + if (n < 0) Expects(current_ - begin_ >= -n); + current_ += n; + return *this; } - friend constexpr span_iterator operator+(difference_type n, span_iterator const& rhs) noexcept + constexpr span_iterator operator+(const difference_type n) const noexcept + { + span_iterator ret = *this; + ret += n; + return ret; + } + + friend constexpr span_iterator operator+(const difference_type n, + const span_iterator& rhs) noexcept { return rhs + n; } - constexpr span_iterator& operator+=(difference_type n) noexcept + constexpr span_iterator& operator-=(const difference_type n) noexcept { - Expects((index_ + n) >= 0 && (index_ + n) <= span_->size()); - index_ += n; + if (n != 0) Expects(begin_ && current_ && end_); + if (n > 0) Expects(current_ - begin_ >= n); + if (n < 0) Expects(end_ - current_ >= -n); + current_ -= n; return *this; } - constexpr span_iterator operator-(difference_type n) const noexcept + constexpr span_iterator operator-(const difference_type n) const noexcept { - auto ret = *this; - return ret -= n; + span_iterator ret = *this; + ret -= n; + return ret; } - constexpr span_iterator& operator-=(difference_type n) noexcept { return *this += -n; } - - constexpr difference_type operator-(span_iterator rhs) const noexcept + template < + class Type2, + std::enable_if_t, value_type>::value, int> = 0> + constexpr difference_type operator-(const span_iterator& rhs) const noexcept { - Expects(span_ == rhs.span_); - return index_ - rhs.index_; + Expects(begin_ == rhs.begin_ && end_ == rhs.end_); + return current_ - rhs.current_; } - constexpr reference operator[](difference_type n) const noexcept { return *(*this + n); } - - constexpr friend bool operator==(span_iterator lhs, span_iterator rhs) noexcept + constexpr reference operator[](const difference_type n) const noexcept { - return lhs.span_ == rhs.span_ && lhs.index_ == rhs.index_; + return *(*this + n); } - constexpr friend bool operator!=(span_iterator lhs, span_iterator rhs) noexcept + template < + class Type2, + std::enable_if_t, value_type>::value, int> = 0> + constexpr bool operator==(const span_iterator& rhs) const noexcept { - return !(lhs == rhs); + Expects(begin_ == rhs.begin_ && end_ == rhs.end_); + return current_ == rhs.current_; } - constexpr friend bool operator<(span_iterator lhs, span_iterator rhs) noexcept + template < + class Type2, + std::enable_if_t, value_type>::value, int> = 0> + constexpr bool operator!=(const span_iterator& rhs) const noexcept { - return lhs.index_ < rhs.index_; + return !(*this == rhs); } - constexpr friend bool operator<=(span_iterator lhs, span_iterator rhs) noexcept + template < + class Type2, + std::enable_if_t, value_type>::value, int> = 0> + constexpr bool operator<(const span_iterator& rhs) const noexcept { - return !(rhs < lhs); + Expects(begin_ == rhs.begin_ && end_ == rhs.end_); + return current_ < rhs.current_; } - constexpr friend bool operator>(span_iterator lhs, span_iterator rhs) noexcept + template < + class Type2, + std::enable_if_t, value_type>::value, int> = 0> + constexpr bool operator>(const span_iterator& rhs) const noexcept { - return rhs < lhs; + return rhs < *this; } - constexpr friend bool operator>=(span_iterator lhs, span_iterator rhs) noexcept + template < + class Type2, + std::enable_if_t, value_type>::value, int> = 0> + constexpr bool operator<=(const span_iterator& rhs) const noexcept { - return !(rhs > lhs); + return !(rhs < *this); + } + + template < + class Type2, + std::enable_if_t, value_type>::value, int> = 0> + constexpr bool operator>=(const span_iterator& rhs) const noexcept + { + return !(*this < rhs); } #ifdef _MSC_VER @@ -262,22 +292,26 @@ namespace details // algorithm calls friend constexpr void _Verify_range(span_iterator lhs, span_iterator rhs) noexcept { // test that [lhs, rhs) forms a valid range inside an STL algorithm - Expects(lhs.span_ == rhs.span_ // range spans have to match - && lhs.index_ <= rhs.index_); // range must not be transposed + Expects(lhs.begin_ == rhs.begin_ // range spans have to match + && lhs.end_ == rhs.end_ && + lhs.current_ <= rhs.current_); // range must not be transposed } constexpr void _Verify_offset(const difference_type n) const noexcept - { // test that the iterator *this + n is a valid range in an STL - // algorithm call - Expects((index_ + n) >= 0 && (index_ + n) <= span_->size()); + { // test that *this + n is within the range of this call + if (n != 0) Expects(begin_ && current_ && end_); + if (n > 0) Expects(end_ - current_ >= n); + if (n < 0) Expects(current_ - begin_ >= -n); } + // clang-format off GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute + // clang-format on constexpr pointer _Unwrapped() const noexcept { // after seeking *this to a high water mark, or using one of the // _Verify_xxx functions above, unwrap this span_iterator to a raw // pointer - return span_->data() + index_; + return current_; } // Tell the STL that span_iterator should not be unwrapped if it can't @@ -287,61 +321,64 @@ namespace details #else static constexpr bool _Unwrap_when_unverified = false; #endif + // clang-format off GSL_SUPPRESS(con.3) // NO-FORMAT: attribute // TODO: false positive + // clang-format on constexpr void _Seek_to(const pointer p) noexcept { // adjust the position of *this to previously verified location p // after _Unwrapped - index_ = p - span_->data(); + current_ = p; } #endif - protected: - const Span* span_ = nullptr; - std::ptrdiff_t index_ = 0; + pointer begin_ = nullptr; + pointer end_ = nullptr; + pointer current_ = nullptr; }; - template + template class extent_type { public: - using index_type = std::ptrdiff_t; + using size_type = std::size_t; - static_assert(Ext >= 0, "A fixed-size span must be >= 0 in size."); + constexpr extent_type() noexcept = default; - constexpr extent_type() noexcept {} - - template + template constexpr extent_type(extent_type ext) { - static_assert(Other == Ext || Other == dynamic_extent, + static_assert(Other == Ext, "Mismatch between fixed-size extent and size of initializing data."); Expects(ext.size() == Ext); } - constexpr extent_type(index_type size) { Expects(size == Ext); } + constexpr extent_type(size_type size) { Expects(size == Ext); } - constexpr index_type size() const noexcept { return Ext; } + constexpr size_type size() const noexcept { return Ext; } }; template <> class extent_type { public: - using index_type = std::ptrdiff_t; + using size_type = std::size_t; - template + template explicit constexpr extent_type(extent_type ext) : size_(ext.size()) {} - explicit constexpr extent_type(index_type size) : size_(size) { Expects(size >= 0); } + explicit constexpr extent_type(size_type size) : size_(size) + { + Expects(size != dynamic_extent); + } - constexpr index_type size() const noexcept { return size_; } + constexpr size_type size() const noexcept { return size_; } private: - index_type size_; + size_type size_; }; - template + template struct calculate_subspan_type { using type = span +template class span { public: // constants and types using element_type = ElementType; using value_type = std::remove_cv_t; - using index_type = std::ptrdiff_t; + using size_type = std::size_t; using pointer = element_type*; + using const_pointer = const element_type*; using reference = element_type&; + using const_reference = const element_type&; + using difference_type = std::ptrdiff_t; - using iterator = details::span_iterator, false>; - using const_iterator = details::span_iterator, true>; + using iterator = details::span_iterator; + using const_iterator = details::span_iterator; using reverse_iterator = std::reverse_iterator; using const_reverse_iterator = std::reverse_iterator; - using size_type = index_type; - #if defined(GSL_USE_STATIC_CONSTEXPR_WORKAROUND) - static constexpr const index_type extent{Extent}; + static constexpr const size_type extent{Extent}; #else - static constexpr index_type extent{Extent}; + static constexpr size_type extent{Extent}; #endif // [span.cons], span constructors, copy, assignment, and destructor template " SFINAE, - // since "std::enable_if_t" is ill-formed when Extent is greater than 0. - class = std::enable_if_t<(Dependent || Extent <= 0)>> + // "Dependent" is needed to make "std::enable_if_t" SFINAE, since "std::enable_if_t" is ill-formed when Extent is greater than 0. + class = std::enable_if_t<(Dependent || + details::is_allowed_extent_conversion<0, Extent>::value)>> constexpr span() noexcept : storage_(nullptr, details::extent_type<0>()) {} - constexpr span(pointer ptr, index_type count) noexcept: storage_(ptr, count) {} + constexpr span(pointer ptr, size_type count) noexcept : storage_(ptr, count) + { + if (Extent != dynamic_extent) Expects(count == Extent); + } constexpr span(pointer firstElem, pointer lastElem) noexcept - : storage_(firstElem, std::distance(firstElem, lastElem)) - {} + : storage_(firstElem, static_cast(lastElem - firstElem)) + { + if (Extent != dynamic_extent) + { Expects(lastElem - firstElem == static_cast(Extent)); } + } - template + template ::value, int> = 0> constexpr span(element_type (&arr)[N]) noexcept - : storage_(KnownNotNull{std::addressof(arr[0])}, details::extent_type()) + : storage_(KnownNotNull{arr + 0}, details::extent_type()) {} - template 0)>> - constexpr span(std::array, N>& arr) noexcept + template ::value, int> = 0> + constexpr span(std::array& arr) noexcept : storage_(KnownNotNull{arr.data()}, details::extent_type()) - { - } + {} - constexpr span(std::array, 0>&) noexcept - : storage_(static_cast(nullptr), details::extent_type<0>()) - { - } - - template 0)>> - constexpr span(const std::array, N>& arr) noexcept + template ::value && + details::is_allowed_element_type_conversion::value), + int> = 0> + constexpr span(const std::array& arr) noexcept : storage_(KnownNotNull{arr.data()}, details::extent_type()) - { - } + {} - constexpr span(const std::array, 0>&) noexcept - : storage_(static_cast(nullptr), details::extent_type<0>()) - { - } - - // NB: the SFINAE here uses .data() as a incomplete/imperfect proxy for the requirement + // NB: the SFINAE here uses .data() as an incomplete/imperfect proxy for the requirement // on Container to be a contiguous sequence container. template ::value && !details::is_std_array::value && - std::is_convertible::value && - std::is_convertible().data())>::value>> - constexpr span(Container& cont) noexcept : span(cont.data(), narrow(cont.size())) + std::is_pointer().data())>::value && + std::is_convertible().data())>(*)[], element_type(*)[]>::value>> + constexpr span(Container& cont) noexcept : span(cont.data(), cont.size()) {} template ::value && !details::is_span::value && - std::is_convertible::value && - std::is_convertible().data())>::value>> - constexpr span(const Container& cont) noexcept : span(cont.data(), narrow(cont.size())) + !details::is_std_array::value && + std::is_pointer().data())>::value && + std::is_convertible().data())>(*)[], element_type(*)[]>::value>> + constexpr span(const Container& cont) noexcept : span(cont.data(), cont.size()) {} constexpr span(const span& other) noexcept = default; template < - class OtherElementType, std::ptrdiff_t OtherExtent, + class OtherElementType, std::size_t OtherExtent, class = std::enable_if_t< details::is_allowed_extent_conversion::value && details::is_allowed_element_type_conversion::value>> @@ -451,62 +490,72 @@ public: constexpr span& operator=(const span& other) noexcept = default; // [span.sub], span subviews - template + template constexpr span first() const noexcept { - Expects(Count >= 0 && Count <= size()); + Expects(Count <= size()); return {data(), Count}; } - template + template + // clang-format off GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute + // clang-format on constexpr span last() const noexcept { - Expects(Count >= 0 && size() - Count >= 0); + Expects(Count <= size()); return {data() + (size() - Count), Count}; } - template + template + // clang-format off GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute + // clang-format on constexpr auto subspan() const noexcept -> - typename details::calculate_subspan_type::type + typename details::calculate_subspan_type::type { - Expects((Offset >= 0 && size() - Offset >= 0) && - (Count == dynamic_extent || (Count >= 0 && Offset + Count <= size()))); + Expects((size() >= Offset) && (Count == dynamic_extent || (Count <= size() - Offset))); return {data() + Offset, Count == dynamic_extent ? size() - Offset : Count}; } - constexpr span first(index_type count) const noexcept + constexpr span first(size_type count) const noexcept { - Expects(count >= 0 && count <= size()); + Expects(count <= size()); return {data(), count}; } - constexpr span last(index_type count) const noexcept + constexpr span last(size_type count) const noexcept { + Expects(count <= size()); return make_subspan(size() - count, dynamic_extent, subspan_selector{}); } - constexpr span subspan(index_type offset, - index_type count = dynamic_extent) const noexcept + constexpr span subspan(size_type offset, + size_type count = dynamic_extent) const + noexcept { return make_subspan(offset, count, subspan_selector{}); } // [span.obs], span observers - constexpr index_type size() const noexcept { return storage_.size(); } - constexpr index_type size_bytes() const noexcept + constexpr size_type size() const noexcept { return storage_.size(); } + + constexpr size_type size_bytes() const noexcept { - return size() * narrow_cast(sizeof(element_type)); + Expects(size() < dynamic_extent / sizeof(element_type)); + return size() * sizeof(element_type); } + constexpr bool empty() const noexcept { return size() == 0; } // [span.elem], span element access + // clang-format off GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute - constexpr reference operator[](index_type idx) const noexcept + // clang-format on + constexpr reference operator[](size_type idx) const noexcept { - Expects(CheckRange(idx, storage_.size())); + Expects(idx < size()); return data()[idx]; } @@ -521,23 +570,35 @@ public: Expects(size() > 0); return data()[size() - 1]; } - - // at and operator() are deprecated to align to the public member functions of std::span - [[deprecated("Use operator[]")]] - constexpr reference at(index_type idx) const noexcept{ return this->operator[](idx); } - [[deprecated("Use operator[]")]] - constexpr reference operator()(index_type idx) const noexcept{ return this->operator[](idx); } - - constexpr pointer data() const noexcept { return storage_.data(); } // [span.iter], span iterator support - constexpr iterator begin() const noexcept { return {this, 0}; } - constexpr iterator end() const noexcept { return {this, size()}; } + constexpr iterator begin() const noexcept + { + const auto data = storage_.data(); + return {data, data + size(), data}; + } - constexpr const_iterator cbegin() const noexcept { return {this, 0}; } - constexpr const_iterator cend() const noexcept { return {this, size()}; } + constexpr iterator end() const noexcept + { + const auto data = storage_.data(); + const auto endData = data + storage_.size(); + return {data, endData, endData}; + } + + constexpr const_iterator cbegin() const noexcept + { + const auto data = storage_.data(); + return {data, data + size(), data}; + } + + constexpr const_iterator cend() const noexcept + { + const auto data = storage_.data(); + const auto endData = data + storage_.size(); + return {data, endData, endData}; + } constexpr reverse_iterator rbegin() const noexcept { return reverse_iterator{end()}; } constexpr reverse_iterator rend() const noexcept { return reverse_iterator{begin()}; } @@ -556,38 +617,14 @@ public: constexpr pointer _Unchecked_begin() const noexcept { return data(); } constexpr pointer _Unchecked_end() const noexcept { + // clang-format off GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute + // clang-format on return data() + size(); } #endif // _MSC_VER private: - static constexpr bool CheckRange(index_type idx, index_type size) noexcept - { - // Optimization: - // - // idx >= 0 && idx < size - // => - // static_cast(idx) < static_cast(size) - // - // because size >=0 by span construction, and negative idx will - // wrap around to a value always greater than size when casted. - - // check if we have enough space to wrap around -#if defined(__cpp_if_constexpr) - if constexpr (sizeof(index_type) <= sizeof(size_t)) -#else - if (sizeof(index_type) <= sizeof(size_t)) -#endif - { - return narrow_cast(idx) < narrow_cast(size); - } - else - { - return idx >= 0 && idx < size; - } - } - // Needed to remove unnecessary null check in subspans struct KnownNotNull { @@ -607,13 +644,13 @@ private: constexpr storage_type(KnownNotNull data, OtherExtentType ext) : ExtentType(ext), data_(data.p) { - Expects(ExtentType::size() >= 0); + Expects(ExtentType::size() != dynamic_extent); } template constexpr storage_type(pointer data, OtherExtentType ext) : ExtentType(ext), data_(data) { - Expects(ExtentType::size() >= 0); + Expects(ExtentType::size() != dynamic_extent); Expects(data || ExtentType::size() == 0); } @@ -627,76 +664,55 @@ private: // The rest is needed to remove unnecessary null check // in subspans and constructors from arrays - constexpr span(KnownNotNull ptr, index_type count) : storage_(ptr, count) {} + constexpr span(KnownNotNull ptr, size_type count) noexcept : storage_(ptr, count) {} - template + template class subspan_selector { }; - template - span make_subspan(index_type offset, index_type count, - subspan_selector) const + template + constexpr span make_subspan(size_type offset, size_type count, + subspan_selector) const noexcept { const span tmp(*this); return tmp.subspan(offset, count); } + // clang-format off GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute - span make_subspan(index_type offset, index_type count, - subspan_selector) const + // clang-format on + constexpr span + make_subspan(size_type offset, size_type count, subspan_selector) const noexcept { - Expects(offset >= 0 && size() - offset >= 0); + Expects(size() >= offset); if (count == dynamic_extent) { return {KnownNotNull{data() + offset}, size() - offset}; } - Expects(count >= 0 && size() - offset >= count); + Expects(size() - offset >= count); return {KnownNotNull{data() + offset}, count}; } }; +#if (defined(__cpp_deduction_guides) && (__cpp_deduction_guides >= 201611L)) + +// Deduction Guides +template +span(Type (&)[Extent])->span; + +template +span(std::array&)->span; + +template +span(const std::array&)->span; + +#endif // ( defined(__cpp_deduction_guides) && (__cpp_deduction_guides >= 201611L) ) + #if defined(GSL_USE_STATIC_CONSTEXPR_WORKAROUND) -template -constexpr const typename span::index_type span::extent; +template +constexpr const typename span::size_type span::extent; #endif -// [span.comparison], span comparison operators -template -constexpr bool operator==(span l, span r) -{ - return std::equal(l.begin(), l.end(), r.begin(), r.end()); -} - -template -constexpr bool operator!=(span l, span r) -{ - return !(l == r); -} - -template -constexpr bool operator<(span l, span r) -{ - return std::lexicographical_compare(l.begin(), l.end(), r.begin(), r.end()); -} - -template -constexpr bool operator<=(span l, span r) -{ - return !(l > r); -} - -template -constexpr bool operator>(span l, span r) -{ - return r < l; -} - -template -constexpr bool operator>=(span l, span r) -{ - return !(l < r); -} - namespace details { // if we only supported compilers with good constexpr support then @@ -705,149 +721,41 @@ namespace details // we should use a narrow_cast<> to go to std::size_t, but older compilers may not see it as // constexpr // and so will fail compilation of the template - template - struct calculate_byte_size - : std::integral_constant(sizeof(ElementType) * - static_cast(Extent))> + template + struct calculate_byte_size : std::integral_constant { + static_assert(Extent < dynamic_extent / sizeof(ElementType), "Size is too big."); }; template struct calculate_byte_size - : std::integral_constant + : std::integral_constant { }; } // namespace details // [span.objectrep], views of object representation -template +template span::value> as_bytes(span s) noexcept { + // clang-format off GSL_SUPPRESS(type.1) // NO-FORMAT: attribute + // clang-format on return {reinterpret_cast(s.data()), s.size_bytes()}; } -template ::value>> +template ::value, int> = 0> span::value> -as_writeable_bytes(span s) noexcept +as_writable_bytes(span s) noexcept { + // clang-format off GSL_SUPPRESS(type.1) // NO-FORMAT: attribute + // clang-format on return {reinterpret_cast(s.data()), s.size_bytes()}; } -// -// make_span() - Utility functions for creating spans -// -template -constexpr span make_span(ElementType* ptr, - typename span::index_type count) -{ - return span(ptr, count); -} - -template -constexpr span make_span(ElementType* firstElem, ElementType* lastElem) -{ - return span(firstElem, lastElem); -} - -template -constexpr span make_span(ElementType (&arr)[N]) noexcept -{ - return span(arr); -} - -template -constexpr span make_span(Container& cont) -{ - return span(cont); -} - -template -constexpr span make_span(const Container& cont) -{ - return span(cont); -} - -template -constexpr span make_span(Ptr& cont, std::ptrdiff_t count) -{ - return span(cont, count); -} - -template -constexpr span make_span(Ptr& cont) -{ - return span(cont); -} - -// Specialization of gsl::at for span -template -constexpr ElementType& at(span s, index i) -{ - // No bounds checking here because it is done in span::operator[] called below - return s[i]; -} - -// [span.obs] Free observer functions -template -constexpr typename span::index_type ssize(const span &span) noexcept -{ - return span.size(); -} - -// [span.iter] Free functions for begin/end functions -template -constexpr typename span::iterator begin(const span &span) noexcept -{ - return span.begin(); -} - -template -constexpr typename span::iterator end(const span &span) noexcept -{ - return span.end(); -} - -template -constexpr typename span::const_iterator cbegin(const span &span) noexcept -{ - return span.cbegin(); -} - -template -constexpr typename span::const_iterator cend(const span &span) noexcept -{ - return span.cend(); -} - -template -constexpr typename span::reverse_iterator rbegin(const span &span) noexcept -{ - return span.rbegin(); -} - -template -constexpr typename span::reverse_iterator rend(const span &span) noexcept -{ - return span.rend(); -} - -template -constexpr typename span::const_reverse_iterator crbegin(const span &span) noexcept -{ - return span.crbegin(); -} - -template -constexpr typename span::const_reverse_iterator crend(const span &span) noexcept -{ - return span.crend(); -} - } // namespace gsl #if defined(_MSC_VER) && !defined(__clang__) diff --git a/include/gsl/span_ext b/include/gsl/span_ext new file mode 100644 index 0000000..b466df8 --- /dev/null +++ b/include/gsl/span_ext @@ -0,0 +1,198 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Copyright (c) 2015 Microsoft Corporation. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef GSL_SPAN_EXT_H +#define GSL_SPAN_EXT_H + +/////////////////////////////////////////////////////////////////////////////// +// +// File: span_ext +// Purpose: continue offering features that have been cut from the official +// implementation of span. +// While modernizing gsl::span a number of features needed to be removed to +// be compliant with the design of std::span +// +/////////////////////////////////////////////////////////////////////////////// + + +#include // for narrow_cast, narrow +#include // for span + +#include // for lexicographical_compare +#include // for ptrdiff_t, size_t +#include + +namespace gsl +{ + +// [span.comparison], span comparison operators +template +constexpr bool operator==(span l, span r) +{ + return std::equal(l.begin(), l.end(), r.begin(), r.end()); +} + +template +constexpr bool operator!=(span l, span r) +{ + return !(l == r); +} + +template +constexpr bool operator<(span l, span r) +{ + return std::lexicographical_compare(l.begin(), l.end(), r.begin(), r.end()); +} + +template +constexpr bool operator<=(span l, span r) +{ + return !(l > r); +} + +template +constexpr bool operator>(span l, span r) +{ + return r < l; +} + +template +constexpr bool operator>=(span l, span r) +{ + return !(l < r); +} + +// +// make_span() - Utility functions for creating spans +// +template +constexpr span make_span(ElementType* ptr, typename span::size_type count) +{ + return span(ptr, count); +} + +template +constexpr span make_span(ElementType* firstElem, ElementType* lastElem) +{ + return span(firstElem, lastElem); +} + +template +constexpr span make_span(ElementType (&arr)[N]) noexcept +{ + return span(arr); +} + +template +constexpr span make_span(Container& cont) +{ + return span(cont); +} + +template +constexpr span make_span(const Container& cont) +{ + return span(cont); +} + +template +constexpr span make_span(Ptr& cont, std::size_t count) +{ + return span(cont, count); +} + +template +constexpr span make_span(Ptr& cont) +{ + return span(cont); +} + +// Specialization of gsl::at for span +template +constexpr ElementType& at(span s, index i) +{ + // No bounds checking here because it is done in span::operator[] called below + Ensures(i >= 0); + return s[narrow_cast(i)]; +} + +// [span.obs] Free observer functions +template +constexpr std::ptrdiff_t ssize(const span& s) noexcept +{ + return static_cast(s.size()); +} + +// [span.iter] Free functions for begin/end functions +template +constexpr typename span::iterator +begin(const span& s) noexcept +{ + return s.begin(); +} + +template +constexpr typename span::iterator +end(const span& s) noexcept +{ + return s.end(); +} + +template +constexpr typename span::const_iterator +cbegin(const span& s) noexcept +{ + return s.cbegin(); +} + +template +constexpr typename span::const_iterator +cend(const span& s) noexcept +{ + return s.cend(); +} + +template +constexpr typename span::reverse_iterator +rbegin(const span& s) noexcept +{ + return s.rbegin(); +} + +template +constexpr typename span::reverse_iterator +rend(const span& s) noexcept +{ + return s.rend(); +} + +template +constexpr typename span::const_reverse_iterator +crbegin(const span& s) noexcept +{ + return s.crbegin(); +} + +template +constexpr typename span::const_reverse_iterator +crend(const span& s) noexcept +{ + return s.crend(); +} + +} // namespace gsl + +#endif // GSL_SPAN_EXT_H diff --git a/include/gsl/string_span b/include/gsl/string_span index 37cbe15..2207291 100644 --- a/include/gsl/string_span +++ b/include/gsl/string_span @@ -19,14 +19,14 @@ #include // for Ensures, Expects #include // for narrow_cast -#include // for operator!=, operator==, dynamic_extent +#include // for operator!=, operator==, dynamic_extent #include // for equal, lexicographical_compare #include // for array -#include // for ptrdiff_t, size_t, nullptr_t +#include // for size_t, nullptr_t #include // for PTRDIFF_MAX #include -#include // for basic_string, allocator, char_traits +#include // for basic_string, allocator, char_traits #include // for declval, is_convertible, enable_if_t, add_... #if defined(_MSC_VER) && !defined(__clang__) @@ -56,43 +56,43 @@ namespace gsl // (sometimes needlessly) break existing programs when introduced. // -template +template using basic_zstring = CharT*; -template +template using czstring = basic_zstring; -template +template using cwzstring = basic_zstring; -template +template using cu16zstring = basic_zstring; -template +template using cu32zstring = basic_zstring; -template +template using zstring = basic_zstring; -template +template using wzstring = basic_zstring; -template +template using u16zstring = basic_zstring; -template +template using u32zstring = basic_zstring; namespace details { template - std::ptrdiff_t string_length(const CharT* str, std::ptrdiff_t n) + std::size_t string_length(const CharT* str, std::size_t n) { - if (str == nullptr || n <= 0) return 0; + if (str == nullptr || n == dynamic_extent) return 0; const span str_span{str, n}; - std::ptrdiff_t len = 0; + std::size_t len = 0; while (len < n && str_span[len]) len++; return len; @@ -108,18 +108,20 @@ namespace details // Will fail-fast if sentinel cannot be found before max elements are examined. // template -span ensure_sentinel(T* seq, std::ptrdiff_t max = PTRDIFF_MAX) +span ensure_sentinel(T* seq, + std::size_t max = static_cast(-1)) { Ensures(seq != nullptr); - GSL_SUPPRESS(f.23) // NO-FORMAT: attribute // TODO: false positive // TODO: suppress does not work + GSL_SUPPRESS( + f.23) // NO-FORMAT: attribute // TODO: false positive // TODO: suppress does not work auto cur = seq; Ensures(cur != nullptr); // workaround for removing the warning GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute // TODO: suppress does not work - while ((cur - seq) < max && *cur != Sentinel) ++cur; + while (static_cast(cur - seq) < max && *cur != Sentinel) ++cur; Ensures(*cur == Sentinel); - return {seq, cur - seq}; + return {seq, static_cast(cur - seq)}; } // @@ -128,7 +130,8 @@ span ensure_sentinel(T* seq, std::ptrdiff_t max = PTRDIFF_MAX // the limit of size_type. // template -span ensure_z(CharT* const& sz, std::ptrdiff_t max = PTRDIFF_MAX) +span ensure_z(CharT* const& sz, + std::size_t max = static_cast(-1)) { return ensure_sentinel(sz, max); } @@ -136,26 +139,27 @@ span ensure_z(CharT* const& sz, std::ptrdiff_t max = PTRD template span ensure_z(CharT (&sz)[N]) { - return ensure_z(&sz[0], narrow_cast(N)); + return ensure_z(&sz[0], N); } template span::type, dynamic_extent> ensure_z(Cont& cont) { - return ensure_z(cont.data(), narrow_cast(cont.size())); + return ensure_z(cont.data(), cont.size()); } -template +template class basic_string_span; -namespace details { +namespace details +{ template struct is_basic_string_span_oracle : std::false_type { }; - template + template struct is_basic_string_span_oracle> : std::true_type { }; @@ -169,7 +173,7 @@ namespace details { // // string_span and relatives // -template +template class basic_string_span { public: @@ -180,14 +184,12 @@ public: using const_reference = std::add_lvalue_reference_t>; using impl_type = span; - using index_type = typename impl_type::index_type; + using size_type = typename impl_type::size_type; using iterator = typename impl_type::iterator; using const_iterator = typename impl_type::const_iterator; using reverse_iterator = typename impl_type::reverse_iterator; using const_reverse_iterator = typename impl_type::const_reverse_iterator; - using size_type = index_type; - // default (empty) constexpr basic_string_span() noexcept = default; @@ -197,7 +199,7 @@ public: // assign constexpr basic_string_span& operator=(const basic_string_span& other) noexcept = default; - constexpr basic_string_span(pointer ptr, index_type length) : span_(ptr, length) {} + constexpr basic_string_span(pointer ptr, size_type length) : span_(ptr, length) {} constexpr basic_string_span(pointer firstElem, pointer lastElem) : span_(firstElem, lastElem) {} // From static arrays - if 0-terminated, remove 0 from the view @@ -218,7 +220,7 @@ public: template // GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute // TODO: parser bug constexpr basic_string_span(std::basic_string& str) - : span_(&str[0], narrow_cast(str.length())) + : span_(&str[0], str.length()) {} template @@ -247,56 +249,56 @@ public: // from string_span template < - class OtherValueType, std::ptrdiff_t OtherExtent, + class OtherValueType, std::size_t OtherExtent, class = std::enable_if_t::impl_type, impl_type>::value>> constexpr basic_string_span(basic_string_span other) : span_(other.data(), other.length()) {} - template + template constexpr basic_string_span first() const { return {span_.template first()}; } - constexpr basic_string_span first(index_type count) const + constexpr basic_string_span first(size_type count) const { return {span_.first(count)}; } - template + template constexpr basic_string_span last() const { return {span_.template last()}; } - constexpr basic_string_span last(index_type count) const + constexpr basic_string_span last(size_type count) const { return {span_.last(count)}; } - template + template constexpr basic_string_span subspan() const { return {span_.template subspan()}; } constexpr basic_string_span - subspan(index_type offset, index_type count = dynamic_extent) const + subspan(size_type offset, size_type count = dynamic_extent) const { return {span_.subspan(offset, count)}; } - constexpr reference operator[](index_type idx) const { return span_[idx]; } - constexpr reference operator()(index_type idx) const { return span_[idx]; } + constexpr reference operator[](size_type idx) const { return span_[idx]; } + constexpr reference operator()(size_type idx) const { return span_[idx]; } constexpr pointer data() const { return span_.data(); } - constexpr index_type length() const noexcept { return span_.size(); } - constexpr index_type size() const noexcept { return span_.size(); } - constexpr index_type size_bytes() const noexcept { return span_.size_bytes(); } - constexpr index_type length_bytes() const noexcept { return span_.length_bytes(); } + constexpr size_type length() const noexcept { return span_.size(); } + constexpr size_type size() const noexcept { return span_.size(); } + constexpr size_type size_bytes() const noexcept { return span_.size_bytes(); } + constexpr size_type length_bytes() const noexcept { return span_.length_bytes(); } constexpr bool empty() const noexcept { return size() == 0; } constexpr iterator begin() const noexcept { return span_.begin(); } @@ -312,7 +314,7 @@ public: constexpr const_reverse_iterator crend() const noexcept { return span_.crend(); } private: - static impl_type remove_z(pointer const& sz, std::ptrdiff_t max) + static impl_type remove_z(pointer const& sz, std::size_t max) { return {sz, details::string_length(sz, max)}; } @@ -320,41 +322,41 @@ private: template static impl_type remove_z(element_type (&sz)[N]) { - return remove_z(&sz[0], narrow_cast(N)); + return remove_z(&sz[0], N); } impl_type span_; }; -template +template using string_span = basic_string_span; -template +template using cstring_span = basic_string_span; -template +template using wstring_span = basic_string_span; -template +template using cwstring_span = basic_string_span; -template +template using u16string_span = basic_string_span; -template +template using cu16string_span = basic_string_span; -template +template using u32string_span = basic_string_span; -template +template using cu32string_span = basic_string_span; // // to_string() allow (explicit) conversions from string_span to string // -template +template std::basic_string::type> to_string(basic_string_span view) { @@ -362,13 +364,13 @@ to_string(basic_string_span view) } template , - typename Allocator = std::allocator, typename gCharT, std::ptrdiff_t Extent> + typename Allocator = std::allocator, typename gCharT, std::size_t Extent> std::basic_string to_basic_string(basic_string_span view) { return {view.data(), narrow_cast(view.length())}; } -template +template basic_string_span::value> as_bytes(basic_string_span s) noexcept { @@ -376,10 +378,10 @@ as_bytes(basic_string_span s) noexcept return {reinterpret_cast(s.data()), s.size_bytes()}; } -template ::value>> basic_string_span::value> -as_writeable_bytes(basic_string_span s) noexcept +as_writable_bytes(basic_string_span s) noexcept { GSL_SUPPRESS(type.1) // NO-FORMAT: attribute return {reinterpret_cast(s.data()), s.size_bytes()}; @@ -387,8 +389,9 @@ as_writeable_bytes(basic_string_span s) noexcept // zero-terminated string span, used to convert // zero-terminated spans to legacy strings -template -class basic_zstring_span { +template +class basic_zstring_span +{ public: using value_type = CharT; using const_value_type = std::add_const_t; @@ -435,32 +438,32 @@ private: impl_type span_; }; -template +template using zstring_span = basic_zstring_span; -template +template using wzstring_span = basic_zstring_span; -template +template using u16zstring_span = basic_zstring_span; -template +template using u32zstring_span = basic_zstring_span; -template +template using czstring_span = basic_zstring_span; -template +template using cwzstring_span = basic_zstring_span; -template +template using cu16zstring_span = basic_zstring_span; -template +template using cu32zstring_span = basic_zstring_span; // operator == -template ::value || std::is_convertible>>::value>> @@ -470,7 +473,7 @@ bool operator==(const gsl::basic_string_span& one, const T& other return std::equal(one.begin(), one.end(), tmp.begin(), tmp.end()); } -template ::value && std::is_convertible>>::value>> @@ -481,7 +484,7 @@ bool operator==(const T& one, const gsl::basic_string_span& other } // operator != -template , Extent>>::value>> bool operator!=(gsl::basic_string_span one, const T& other) @@ -490,7 +493,7 @@ bool operator!=(gsl::basic_string_span one, const T& other) } template < - typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T, + typename CharT, std::size_t Extent = gsl::dynamic_extent, typename T, typename = std::enable_if_t< std::is_convertible, Extent>>::value && !gsl::details::is_basic_string_span::value>> @@ -500,7 +503,7 @@ bool operator!=(const T& one, gsl::basic_string_span other) } // operator< -template , Extent>>::value>> bool operator<(gsl::basic_string_span one, const T& other) @@ -510,7 +513,7 @@ bool operator<(gsl::basic_string_span one, const T& other) } template < - typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T, + typename CharT, std::size_t Extent = gsl::dynamic_extent, typename T, typename = std::enable_if_t< std::is_convertible, Extent>>::value && !gsl::details::is_basic_string_span::value>> @@ -526,7 +529,7 @@ bool operator<(const T& one, gsl::basic_string_span other) // so the cases below are already covered by the previous operators template < - typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T, + typename CharT, std::size_t Extent = gsl::dynamic_extent, typename T, typename DataType = typename T::value_type, typename = std::enable_if_t< !gsl::details::is_span::value && !gsl::details::is_basic_string_span::value && @@ -540,7 +543,7 @@ bool operator<(gsl::basic_string_span one, const T& other) } template < - typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T, + typename CharT, std::size_t Extent = gsl::dynamic_extent, typename T, typename DataType = typename T::value_type, typename = std::enable_if_t< !gsl::details::is_span::value && !gsl::details::is_basic_string_span::value && @@ -555,7 +558,7 @@ bool operator<(const T& one, gsl::basic_string_span other) #endif // operator <= -template , Extent>>::value>> bool operator<=(gsl::basic_string_span one, const T& other) @@ -564,7 +567,7 @@ bool operator<=(gsl::basic_string_span one, const T& other) } template < - typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T, + typename CharT, std::size_t Extent = gsl::dynamic_extent, typename T, typename = std::enable_if_t< std::is_convertible, Extent>>::value && !gsl::details::is_basic_string_span::value>> @@ -579,7 +582,7 @@ bool operator<=(const T& one, gsl::basic_string_span other) // so the cases below are already covered by the previous operators template < - typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T, + typename CharT, std::size_t Extent = gsl::dynamic_extent, typename T, typename DataType = typename T::value_type, typename = std::enable_if_t< !gsl::details::is_span::value && !gsl::details::is_basic_string_span::value && @@ -592,7 +595,7 @@ bool operator<=(gsl::basic_string_span one, const T& other) } template < - typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T, + typename CharT, std::size_t Extent = gsl::dynamic_extent, typename T, typename DataType = typename T::value_type, typename = std::enable_if_t< !gsl::details::is_span::value && !gsl::details::is_basic_string_span::value && @@ -606,7 +609,7 @@ bool operator<=(const T& one, gsl::basic_string_span other) #endif // operator> -template , Extent>>::value>> bool operator>(gsl::basic_string_span one, const T& other) @@ -615,7 +618,7 @@ bool operator>(gsl::basic_string_span one, const T& other) } template < - typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T, + typename CharT, std::size_t Extent = gsl::dynamic_extent, typename T, typename = std::enable_if_t< std::is_convertible, Extent>>::value && !gsl::details::is_basic_string_span::value>> @@ -630,7 +633,7 @@ bool operator>(const T& one, gsl::basic_string_span other) // so the cases below are already covered by the previous operators template < - typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T, + typename CharT, std::size_t Extent = gsl::dynamic_extent, typename T, typename DataType = typename T::value_type, typename = std::enable_if_t< !gsl::details::is_span::value && !gsl::details::is_basic_string_span::value && @@ -643,7 +646,7 @@ bool operator>(gsl::basic_string_span one, const T& other) } template < - typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T, + typename CharT, std::size_t Extent = gsl::dynamic_extent, typename T, typename DataType = typename T::value_type, typename = std::enable_if_t< !gsl::details::is_span::value && !gsl::details::is_basic_string_span::value && @@ -657,7 +660,7 @@ bool operator>(const T& one, gsl::basic_string_span other) #endif // operator >= -template , Extent>>::value>> bool operator>=(gsl::basic_string_span one, const T& other) @@ -666,7 +669,7 @@ bool operator>=(gsl::basic_string_span one, const T& other) } template < - typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T, + typename CharT, std::size_t Extent = gsl::dynamic_extent, typename T, typename = std::enable_if_t< std::is_convertible, Extent>>::value && !gsl::details::is_basic_string_span::value>> @@ -681,7 +684,7 @@ bool operator>=(const T& one, gsl::basic_string_span other) // so the cases below are already covered by the previous operators template < - typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T, + typename CharT, std::size_t Extent = gsl::dynamic_extent, typename T, typename DataType = typename T::value_type, typename = std::enable_if_t< !gsl::details::is_span::value && !gsl::details::is_basic_string_span::value && @@ -694,7 +697,7 @@ bool operator>=(gsl::basic_string_span one, const T& other) } template < - typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T, + typename CharT, std::size_t Extent = gsl::dynamic_extent, typename T, typename DataType = typename T::value_type, typename = std::enable_if_t< !gsl::details::is_span::value && !gsl::details::is_basic_string_span::value && diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 680bd5e..0219319 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -45,14 +45,38 @@ if(MSVC) # MSVC or simulating MSVC /EHsc /W4 /WX + $<$: + /wd4996 # Use of function or classes marked [[deprecated]] + /wd26409 # CppCoreCheck - GTest + /wd26426 # CppCoreCheck - GTest + /wd26440 # CppCoreCheck - GTest + /wd26446 # CppCoreCheck - prefer gsl::at() + /wd26472 # CppCoreCheck - use gsl::narrow(_cast) + /wd26481 # CppCoreCheck - use span instead of pointer arithmetic + $<$,1920>: # VS2015 + /wd4189 # variable is initialized but not referenced + $<$>: # Release, RelWithDebInfo + /wd4702 # Unreachable code + > + > + > $<$: -Weverything -Wno-c++98-compat -Wno-c++98-compat-pedantic + -Wno-covered-switch-default # GTest + -Wno-deprecated-declarations # Allow tests for [[deprecated]] elements + -Wno-global-constructors # GTest + -Wno-language-extension-token # GTest gtest-port.h -Wno-missing-braces -Wno-missing-prototypes - -Wno-unknown-attributes - $<$:-Wno-unused-member-function> + -Wno-shift-sign-overflow # GTest gtest-port.h + -Wno-undef # GTest + -Wno-used-but-marked-unused # GTest EXPECT_DEATH + $<$: # no support for [[maybe_unused]] + -Wno-unused-member-function + -Wno-unused-variable + > > ) else() @@ -67,16 +91,23 @@ else() -Wpedantic -Wshadow -Wsign-conversion + -Wno-deprecated-declarations # Allow tests for [[deprecated]] elements $<$,$>: -Weverything -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-missing-braces + -Wno-covered-switch-default # GTest + -Wno-global-constructors # GTest -Wno-missing-prototypes -Wno-padded -Wno-unknown-attributes - $<$:-Wno-unused-member-function> + -Wno-used-but-marked-unused # GTest EXPECT_DEATH -Wno-weak-vtables + $<$: # no support for [[maybe_unused]] + -Wno-unused-member-function + -Wno-unused-variable + > > $<$: $<$,4.99>,$,6>>: @@ -88,6 +119,21 @@ else() $<$:-Wno-undefined-func-template> > > + $<$: + -Wdouble-promotion # float implicit to double + -Wlogical-op # suspicious uses of logical operators + $<$,6>>: + -Wduplicated-cond # duplicated if-else conditions + -Wmisleading-indentation + -Wnull-dereference + $<$: # no support for [[maybe_unused]] + -Wno-unused-variable + > + > + $<$,7>>: + -Wduplicated-branches # identical if-else branches + > + > ) endif(MSVC) @@ -114,6 +160,8 @@ function(add_gsl_test name) endfunction() add_gsl_test(span_tests) +add_gsl_test(span_ext_tests) +add_gsl_test(span_compatibility_tests) add_gsl_test(multi_span_tests) add_gsl_test(strided_span_tests) add_gsl_test(string_span_tests) @@ -140,14 +188,18 @@ endforeach(flag_var) # please try to keep entries ordered =) add_library(gsl_tests_config_noexcept INTERFACE) if(MSVC) # MSVC or simulating MSVC + target_compile_definitions(gsl_tests_config_noexcept INTERFACE + _HAS_EXCEPTIONS=0 # disable exceptions in the Microsoft STL + ) target_compile_options(gsl_tests_config_noexcept INTERFACE ${GSL_CPLUSPLUS_OPT} - /EHsc /W4 /WX $<$: /wd4577 /wd4702 + /wd26440 # CppCoreCheck - GTest + /wd26446 # CppCoreCheck - prefer gsl::at() > $<$: -Weverything @@ -178,6 +230,22 @@ else() -Wno-unknown-attributes -Wno-weak-vtables > + $<$: + -Wdouble-promotion # float implicit to double + -Wlogical-op # suspicious uses of logical operators + -Wuseless-cast # casting to its own type + $<$,6>>: + -Wduplicated-cond # duplicated if-else conditions + -Wmisleading-indentation + -Wnull-dereference + > + $<$,7>>: + -Wduplicated-branches # identical if-else branches + > + $<$,8>>: + -Wcast-align=strict # increase alignment (i.e. char* to int*) + > + > ) endif(MSVC) diff --git a/tests/CMakeLists.txt.in b/tests/CMakeLists.txt.in index 50c041d..f380b8f 100644 --- a/tests/CMakeLists.txt.in +++ b/tests/CMakeLists.txt.in @@ -4,7 +4,7 @@ project(googletest-download NONE) include(ExternalProject) ExternalProject_Add(googletest GIT_REPOSITORY https://github.com/google/googletest.git - GIT_TAG master + GIT_TAG 703bd9caab50b139428cea1aaff9974ebee5742e SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-src" BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-build" CONFIGURE_COMMAND "" diff --git a/tests/algorithm_tests.cpp b/tests/algorithm_tests.cpp index 50bff11..ec9b2d1 100644 --- a/tests/algorithm_tests.cpp +++ b/tests/algorithm_tests.cpp @@ -14,25 +14,6 @@ // /////////////////////////////////////////////////////////////////////////////// -#ifdef _MSC_VER -// blanket turn off warnings from CppCoreCheck from catch -// so people aren't annoyed by them when running the tool. -#pragma warning(disable : 26440 26426) // from catch -#endif - -#if __clang__ || __GNUC__ -// disable warnings from gtest -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wundef" -#endif // __clang__ || __GNUC__ - -#if __clang__ -#pragma GCC diagnostic ignored "-Wglobal-constructors" -#pragma GCC diagnostic ignored "-Wused-but-marked-unused" -#pragma GCC diagnostic ignored "-Wcovered-switch-default" -#pragma GCC diagnostic ignored "-Winconsistent-missing-destructor-override" -#endif // __clang__ - #include #include // for copy #include // for span @@ -244,7 +225,3 @@ TEST(algorithm_tests, small_destination_span) copy(src_span_static, dst_span_static); #endif } - -#if __clang__ || __GNUC__ -#pragma GCC diagnostic pop -#endif // __clang__ || __GNUC__ diff --git a/tests/assertion_tests.cpp b/tests/assertion_tests.cpp index 598c7dc..c45b00c 100644 --- a/tests/assertion_tests.cpp +++ b/tests/assertion_tests.cpp @@ -14,25 +14,6 @@ // /////////////////////////////////////////////////////////////////////////////// -#ifdef _MSC_VER -// blanket turn off warnings from CppCoreCheck from catch -// so people aren't annoyed by them when running the tool. -#pragma warning(disable : 26440 26426) // from catch -#endif - -#if __clang__ || __GNUC__ -//disable warnings from gtest -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wundef" -#endif // __clang__ || __GNUC__ - -#if __clang__ -#pragma GCC diagnostic ignored "-Wglobal-constructors" -#pragma GCC diagnostic ignored "-Wused-but-marked-unused" -#pragma GCC diagnostic ignored "-Wcovered-switch-default" -#pragma GCC diagnostic ignored "-Winconsistent-missing-destructor-override" -#endif // __clang__ - #include #include // for fail_fast (ptr only), Ensures, Expects @@ -78,7 +59,3 @@ TEST(assertion_tests, ensures) EXPECT_TRUE(g(2) == 3); EXPECT_DEATH(g(9), deathstring); } - -#if __clang__ || __GNUC__ -#pragma GCC diagnostic pop -#endif // __clang__ || __GNUC__ diff --git a/tests/at_tests.cpp b/tests/at_tests.cpp index cbed5ba..be2c7b8 100644 --- a/tests/at_tests.cpp +++ b/tests/at_tests.cpp @@ -14,25 +14,6 @@ // /////////////////////////////////////////////////////////////////////////////// -#ifdef _MSC_VER -// blanket turn off warnings from CppCoreCheck from catch -// so people aren't annoyed by them when running the tool. -#pragma warning(disable : 26440 26426) // from catch -#endif - -#if __clang__ || __GNUC__ -//disable warnings from gtest -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wundef" -#endif // __clang__ || __GNUC__ - -#if __clang__ -#pragma GCC diagnostic ignored "-Wglobal-constructors" -#pragma GCC diagnostic ignored "-Wused-but-marked-unused" -#pragma GCC diagnostic ignored "-Wcovered-switch-default" -#pragma GCC diagnostic ignored "-Winconsistent-missing-destructor-override" -#endif // __clang__ - #include #include // for at @@ -152,7 +133,3 @@ static constexpr bool test_constexpr() static_assert(test_constexpr(), "FAIL"); #endif - -#if __clang__ || __GNUC__ -#pragma GCC diagnostic pop -#endif // __clang__ || __GNUC__ diff --git a/tests/bounds_tests.cpp b/tests/bounds_tests.cpp index 4291ae1..9c2fb96 100644 --- a/tests/bounds_tests.cpp +++ b/tests/bounds_tests.cpp @@ -14,28 +14,6 @@ // /////////////////////////////////////////////////////////////////////////////// -#ifdef _MSC_VER -// blanket turn off warnings from CppCoreCheck from catch -// so people aren't annoyed by them when running the tool. -#pragma warning(disable : 26440 26426) // from catch -#pragma warning(disable : 4996) // use of function or classes marked [[deprecated]] -#endif - -#if __clang__ || __GNUC__ -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wdeprecated-declarations" - -//disable warnings from gtest -#pragma GCC diagnostic ignored "-Wundef" -#endif // __clang__ || __GNUC__ - -#if __clang__ -#pragma GCC diagnostic ignored "-Wglobal-constructors" -#pragma GCC diagnostic ignored "-Wused-but-marked-unused" -#pragma GCC diagnostic ignored "-Wcovered-switch-default" -#pragma GCC diagnostic ignored "-Winconsistent-missing-destructor-override" -#endif // __clang__ - #include #include // for static_bounds, static_bounds_dynamic_range_t @@ -122,7 +100,3 @@ TEST(bounds_tests, bounds_convertible) #ifdef CONFIRM_COMPILATION_ERRORS copy(src_span_static, dst_span_static); #endif - -#if __clang__ || __GNUC__ -#pragma GCC diagnostic pop -#endif // __clang__ || __GNUC__ diff --git a/tests/byte_tests.cpp b/tests/byte_tests.cpp index ab243a7..f2850ad 100644 --- a/tests/byte_tests.cpp +++ b/tests/byte_tests.cpp @@ -14,25 +14,6 @@ // /////////////////////////////////////////////////////////////////////////////// -#ifdef _MSC_VER -// blanket turn off warnings from CppCoreCheck from catch -// so people aren't annoyed by them when running the tool. -#pragma warning(disable : 26440 26426) -#endif // _MSC_VER - -#if __clang__ || __GNUC__ -//disable warnings from gtest -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wundef" -#endif // __clang__ || __GNUC__ - -#if __clang__ -#pragma GCC diagnostic ignored "-Wglobal-constructors" -#pragma GCC diagnostic ignored "-Wused-but-marked-unused" -#pragma GCC diagnostic ignored "-Wcovered-switch-default" -#pragma GCC diagnostic ignored "-Winconsistent-missing-destructor-override" -#endif // __clang__ - #include #include // for to_byte, to_integer, byte, operator&, ope... @@ -146,7 +127,3 @@ TEST(byte_tests, aliasing) #ifdef CONFIRM_COMPILATION_ERRORS copy(src_span_static, dst_span_static); #endif - -#if __clang__ || __GNUC__ -#pragma GCC diagnostic pop -#endif // __clang__ || __GNUC__ diff --git a/tests/multi_span_tests.cpp b/tests/multi_span_tests.cpp index f2e040f..6425928 100644 --- a/tests/multi_span_tests.cpp +++ b/tests/multi_span_tests.cpp @@ -14,29 +14,6 @@ // /////////////////////////////////////////////////////////////////////////////// -#ifdef _MSC_VER -// blanket turn off warnings from CppCoreCheck from catch -// so people aren't annoyed by them when running the tool. -#pragma warning(disable : 26440 26426) // from catch -#pragma warning(disable : 4996) // multi_span is in the process of being deprecated. - // Suppressing warnings until it is completely removed -#endif - -#if __clang__ || __GNUC__ -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wdeprecated-declarations" - -//disable warnings from gtest -#pragma GCC diagnostic ignored "-Wundef" -#endif // __clang__ || __GNUC__ - -#if __clang__ -#pragma GCC diagnostic ignored "-Wglobal-constructors" -#pragma GCC diagnostic ignored "-Wused-but-marked-unused" -#pragma GCC diagnostic ignored "-Wcovered-switch-default" -#pragma GCC diagnostic ignored "-Winconsistent-missing-destructor-override" -#endif // __clang__ - #include #include // for byte @@ -1884,7 +1861,3 @@ TEST(multi_span_test, iterator) #ifdef CONFIRM_COMPILATION_ERRORS copy(src_span_static, dst_span_static); #endif - -#if __clang__ || __GNUC__ -#pragma GCC diagnostic pop -#endif // __clang__ || __GNUC__ diff --git a/tests/notnull_tests.cpp b/tests/notnull_tests.cpp index 038119e..0578131 100644 --- a/tests/notnull_tests.cpp +++ b/tests/notnull_tests.cpp @@ -14,28 +14,6 @@ // /////////////////////////////////////////////////////////////////////////////// -#ifdef _MSC_VER -// blanket turn off warnings from CppCoreCheck from catch -// so people aren't annoyed by them when running the tool. -#pragma warning(disable : 26440 26426) // from catch - -// Fix VS2015 build breaks in Release -#pragma warning(disable : 4702) // unreachable code -#endif - -#if __clang__ || __GNUC__ -//disable warnings from gtest -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wundef" -#endif // __clang__ || __GNUC__ - -#if __clang__ -#pragma GCC diagnostic ignored "-Wglobal-constructors" -#pragma GCC diagnostic ignored "-Wused-but-marked-unused" -#pragma GCC diagnostic ignored "-Wcovered-switch-default" -#pragma GCC diagnostic ignored "-Winconsistent-missing-destructor-override" -#endif // __clang__ - #include #include // for not_null, operator<, operator<=, operator> @@ -555,10 +533,3 @@ TEST(notnull_tests, TestMakeNotNull) } #endif } - -static_assert(std::is_nothrow_move_constructible>::value, - "not_null must be no-throw move constructible"); - -#if __clang__ || __GNUC__ -#pragma GCC diagnostic pop -#endif // __clang__ || __GNUC__ diff --git a/tests/owner_tests.cpp b/tests/owner_tests.cpp index 8756596..ca8222f 100644 --- a/tests/owner_tests.cpp +++ b/tests/owner_tests.cpp @@ -14,26 +14,6 @@ // /////////////////////////////////////////////////////////////////////////////// -#ifdef _MSC_VER -// blanket turn off warnings from CppCoreCheck from catch -// so people aren't annoyed by them when running the tool. -#pragma warning(disable : 26440 26426) // from catch - -#endif - -#if __clang__ || __GNUC__ -//disable warnings from gtest -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wundef" -#endif // __clang__ || __GNUC__ - -#if __clang__ -#pragma GCC diagnostic ignored "-Wglobal-constructors" -#pragma GCC diagnostic ignored "-Wused-but-marked-unused" -#pragma GCC diagnostic ignored "-Wcovered-switch-default" -#pragma GCC diagnostic ignored "-Winconsistent-missing-destructor-override" -#endif // __clang__ - #include #include // for owner @@ -61,7 +41,3 @@ TEST(owner_tests, check_pointer_constraint) } #endif } - -#if __clang__ || __GNUC__ -#pragma GCC diagnostic pop -#endif // __clang__ || __GNUC__ diff --git a/tests/span_compatibility_tests.cpp b/tests/span_compatibility_tests.cpp new file mode 100644 index 0000000..8733e72 --- /dev/null +++ b/tests/span_compatibility_tests.cpp @@ -0,0 +1,1072 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// 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 + +#include // for byte +#include // for span, span_iterator, operator==, operator!= + +#include // for array +#include // for ptrdiff_t +#include // for reverse_iterator, operator-, operator== +#include // for integral_constant<>::value, is_default_co... +#include +#include // for vector + +using namespace std; +using namespace gsl; + +// Below are tests that verify the gsl interface support the same things as the std +// Ranges and Concepts support need to be added later. + +struct Base +{ +}; +struct Derived : Base +{ +}; +static_assert(std::is_convertible::value, "std::is_convertible"); +static_assert(!std::is_convertible::value, + "!std::is_convertible"); + +TEST(span_compatibility_tests, assertion_tests) +{ + int arr[3]{10, 20, 30}; + std::array stl{{100, 200, 300}}; + + { + gsl::span sp_dyn; + EXPECT_TRUE(sp_dyn.data() == nullptr); + EXPECT_TRUE(sp_dyn.size() == 0); + EXPECT_TRUE(sp_dyn.empty()); + } + { + gsl::span sp_zero; + EXPECT_TRUE(sp_zero.data() == nullptr); + EXPECT_TRUE(sp_zero.size() == 0); + EXPECT_TRUE(sp_zero.empty()); + + gsl::span sp_dyn_a(arr, 3); + gsl::span sp_dyn_b(begin(arr), 3); + EXPECT_TRUE(sp_dyn_a.data() == std::begin(arr)); + EXPECT_TRUE(sp_dyn_b.data() == std::begin(arr)); + EXPECT_TRUE(sp_dyn_a.size() == 3); + EXPECT_TRUE(sp_dyn_b.size() == 3); + + gsl::span sp_three_a(arr, 3); + gsl::span sp_three_b(begin(arr), 3); + EXPECT_TRUE(sp_three_a.data() == std::begin(arr)); + EXPECT_TRUE(sp_three_b.data() == std::begin(arr)); + EXPECT_TRUE(sp_three_a.size() == 3); + EXPECT_TRUE(sp_three_b.size() == 3); + + gsl::span sp_const_a(arr, 3); + gsl::span sp_const_b(begin(arr), 3); + EXPECT_TRUE(sp_const_a.data() == std::begin(arr)); + EXPECT_TRUE(sp_const_b.data() == std::begin(arr)); + EXPECT_TRUE(sp_const_a.size() == 3); + EXPECT_TRUE(sp_const_b.size() == 3); + +#if __cplusplus >= 201703l + gsl::span sp_const_c(std::as_const(arr), 3); + EXPECT_TRUE(sp_const_c.data() == std::begin(arr)); + EXPECT_TRUE(sp_const_c.size() == 3); +#endif // __cplusplus >= 201703l + + gsl::span sp_const_d(cbegin(arr), 3); + EXPECT_TRUE(sp_const_d.data() == std::begin(arr)); + EXPECT_TRUE(sp_const_d.size() == 3); + } + { + gsl::span sp_dyn_a(begin(arr), std::end(arr)); + EXPECT_TRUE(sp_dyn_a.data() == std::begin(arr)); + EXPECT_TRUE(sp_dyn_a.size() == 3); + + gsl::span sp_three_a(begin(arr), std::end(arr)); + EXPECT_TRUE(sp_three_a.data() == std::begin(arr)); + EXPECT_TRUE(sp_three_a.size() == 3); + + gsl::span sp_const_a(begin(arr), std::end(arr)); + gsl::span sp_const_b(begin(arr), std::cend(arr)); + gsl::span sp_const_c(cbegin(arr), std::end(arr)); + gsl::span sp_const_d(cbegin(arr), std::cend(arr)); + EXPECT_TRUE(sp_const_a.data() == std::begin(arr)); + EXPECT_TRUE(sp_const_b.data() == std::begin(arr)); + EXPECT_TRUE(sp_const_c.data() == std::begin(arr)); + EXPECT_TRUE(sp_const_d.data() == std::begin(arr)); + EXPECT_TRUE(sp_const_a.size() == 3); + EXPECT_TRUE(sp_const_b.size() == 3); + EXPECT_TRUE(sp_const_c.size() == 3); + EXPECT_TRUE(sp_const_d.size() == 3); + } + { + gsl::span sp_dyn_a(arr); + gsl::span sp_dyn_b(stl); + gsl::span sp_dyn_c{stl}; + gsl::span sp_dyn_d{stl}; + EXPECT_TRUE(sp_dyn_a.data() == std::begin(arr)); + EXPECT_TRUE(sp_dyn_b.data() == stl.data()); + EXPECT_TRUE(sp_dyn_a.size() == 3); + EXPECT_TRUE(sp_dyn_b.size() == 3); + + gsl::span sp_three_a(arr); + gsl::span sp_three_b(stl); + EXPECT_TRUE(sp_three_a.data() == std::begin(arr)); + EXPECT_TRUE(sp_three_b.data() == stl.data()); + EXPECT_TRUE(sp_three_a.size() == 3); + EXPECT_TRUE(sp_three_b.size() == 3); + + gsl::span sp_const_w(arr); + gsl::span sp_const_y(stl); + EXPECT_TRUE(sp_const_w.data() == std::begin(arr)); + EXPECT_TRUE(sp_const_y.data() == stl.data()); + EXPECT_TRUE(sp_const_w.size() == 3); + EXPECT_TRUE(sp_const_y.size() == 3); + +#if __cplusplus >= 201703l + gsl::span sp_const_x(std::as_const(arr)); + EXPECT_TRUE(sp_const_x.data() == std::begin(arr)); + EXPECT_TRUE(sp_const_x.size() == 3); + + gsl::span sp_const_z(std::as_const(stl)); + EXPECT_TRUE(sp_const_z.data() == stl.data()); + EXPECT_TRUE(sp_const_z.size() == 3); +#endif // __cplusplus >= 201703l + } + { + const gsl::span orig_dyn(arr); + const gsl::span orig_three(arr); + const gsl::span orig_const_dyn(arr); + const gsl::span orig_const_three(arr); + + gsl::span sp_a(orig_dyn); + gsl::span sp_b(orig_three); + + gsl::span sp_c(orig_three); + + gsl::span sp_d(orig_dyn); + gsl::span sp_e(orig_three); + gsl::span sp_f(orig_const_dyn); + gsl::span sp_g(orig_const_three); + + gsl::span sp_h(orig_three); + gsl::span sp_i(orig_const_three); + + EXPECT_TRUE(sp_a.data() == std::begin(arr)); + EXPECT_TRUE(sp_b.data() == std::begin(arr)); + EXPECT_TRUE(sp_c.data() == std::begin(arr)); + EXPECT_TRUE(sp_d.data() == std::begin(arr)); + EXPECT_TRUE(sp_e.data() == std::begin(arr)); + EXPECT_TRUE(sp_f.data() == std::begin(arr)); + EXPECT_TRUE(sp_g.data() == std::begin(arr)); + EXPECT_TRUE(sp_h.data() == std::begin(arr)); + EXPECT_TRUE(sp_i.data() == std::begin(arr)); + EXPECT_TRUE(sp_a.size() == 3); + EXPECT_TRUE(sp_b.size() == 3); + EXPECT_TRUE(sp_c.size() == 3); + EXPECT_TRUE(sp_d.size() == 3); + EXPECT_TRUE(sp_e.size() == 3); + EXPECT_TRUE(sp_f.size() == 3); + EXPECT_TRUE(sp_g.size() == 3); + EXPECT_TRUE(sp_h.size() == 3); + EXPECT_TRUE(sp_i.size() == 3); + } + { + gsl::span sp_dyn(arr); + gsl::span sp_three(arr); + gsl::span sp_const_dyn(arr); + gsl::span sp_const_three(arr); + + EXPECT_TRUE(sp_dyn.data() == std::begin(arr)); + EXPECT_TRUE(sp_three.data() == std::begin(arr)); + EXPECT_TRUE(sp_const_dyn.data() == std::begin(arr)); + EXPECT_TRUE(sp_const_three.data() == std::begin(arr)); + EXPECT_TRUE(sp_dyn.size() == 3); + EXPECT_TRUE(sp_three.size() == 3); + EXPECT_TRUE(sp_const_dyn.size() == 3); + EXPECT_TRUE(sp_const_three.size() == 3); + + int other[4]{12, 34, 56, 78}; + + sp_dyn = gsl::span{other}; + sp_three = gsl::span{stl}; + sp_const_dyn = gsl::span{other}; + sp_const_three = gsl::span{stl}; + + EXPECT_TRUE(sp_dyn.data() == std::begin(other)); + EXPECT_TRUE(sp_three.data() == stl.data()); + EXPECT_TRUE(sp_const_dyn.data() == std::begin(other)); + EXPECT_TRUE(sp_const_three.data() == stl.data()); + EXPECT_TRUE(sp_dyn.size() == 4); + EXPECT_TRUE(sp_three.size() == 3); + EXPECT_TRUE(sp_const_dyn.size() == 4); + EXPECT_TRUE(sp_const_three.size() == 3); + } + { + gsl::span::iterator it_dyn{}; + + { + gsl::span sp_dyn(arr); + it_dyn = sp_dyn.begin(); + } + + EXPECT_TRUE(*it_dyn == arr[0]); + EXPECT_TRUE(it_dyn[2] == arr[2]); + + gsl::span::iterator it_three{}; + + { + gsl::span sp_three(stl); + it_three = sp_three.begin(); + } + + EXPECT_TRUE(*it_three == stl[0]); + EXPECT_TRUE(it_three[2] == stl[2]); + } + + { + int sequence[9]{10, 20, 30, 40, 50, 60, 70, 80, 90}; + + const gsl::span sp_dyn(sequence); + const gsl::span sp_nine(sequence); + + auto first_3 = sp_dyn.first<3>(); + auto first_4 = sp_nine.first<4>(); + auto first_5 = sp_dyn.first(5); + auto first_6 = sp_nine.first(6); + static_assert(noexcept(sp_dyn.first<3>()), "noexcept(sp_dyn.first<3>())"); // strengthened + static_assert(noexcept(sp_nine.first<4>()), "noexcept(sp_nine.first<4>())"); // strengthened + static_assert(noexcept(sp_dyn.first(5)), "noexcept(sp_dyn.first(5))"); // strengthened + static_assert(noexcept(sp_nine.first(6)), "noexcept(sp_nine.first(6))"); // strengthened + static_assert(is_same>::value, + "is_same>::value"); + static_assert(is_same>::value, + "is_same>::value"); + static_assert(is_same>::value, + "is_same>::value"); + static_assert(is_same>::value, + "is_same>::value"); + EXPECT_TRUE(first_3.data() == std::begin(sequence)); + EXPECT_TRUE(first_4.data() == std::begin(sequence)); + EXPECT_TRUE(first_5.data() == std::begin(sequence)); + EXPECT_TRUE(first_6.data() == std::begin(sequence)); + EXPECT_TRUE(first_3.size() == 3); + EXPECT_TRUE(first_4.size() == 4); + EXPECT_TRUE(first_5.size() == 5); + EXPECT_TRUE(first_6.size() == 6); + + auto last_3 = sp_dyn.last<3>(); + auto last_4 = sp_nine.last<4>(); + auto last_5 = sp_dyn.last(5); + auto last_6 = sp_nine.last(6); + static_assert(noexcept(sp_dyn.last<3>()), "noexcept(sp_dyn.last<3>())"); // strengthened + static_assert(noexcept(sp_nine.last<4>()), "noexcept(sp_nine.last<4>())"); // strengthened + static_assert(noexcept(sp_dyn.last(5)), "noexcept(sp_dyn.last(5))"); // strengthened + static_assert(noexcept(sp_nine.last(6)), "noexcept(sp_nine.last(6))"); // strengthened + static_assert(is_same>::value, + "is_same>::value"); + static_assert(is_same>::value, + "is_same>::value"); + static_assert(is_same>::value, + "is_same>::value"); + static_assert(is_same>::value, + "is_same>::value"); + EXPECT_TRUE(last_3.data() == std::begin(sequence) + 6); + EXPECT_TRUE(last_4.data() == std::begin(sequence) + 5); + EXPECT_TRUE(last_5.data() == std::begin(sequence) + 4); + EXPECT_TRUE(last_6.data() == std::begin(sequence) + 3); + EXPECT_TRUE(last_3.size() == 3); + EXPECT_TRUE(last_4.size() == 4); + EXPECT_TRUE(last_5.size() == 5); + EXPECT_TRUE(last_6.size() == 6); + + auto offset_3 = sp_dyn.subspan<3>(); + auto offset_4 = sp_nine.subspan<4>(); + auto offset_5 = sp_dyn.subspan(5); + auto offset_6 = sp_nine.subspan(6); + static_assert(noexcept(sp_dyn.subspan<3>()), + "noexcept(sp_dyn.subspan<3>())"); // strengthened + static_assert(noexcept(sp_nine.subspan<4>()), + "noexcept(sp_nine.subspan<4>())"); // strengthened + static_assert(noexcept(sp_dyn.subspan(5)), "noexcept(sp_dyn.subspan(5))"); // strengthened + static_assert(noexcept(sp_nine.subspan(6)), "noexcept(sp_nine.subspan(6))"); // strengthened + static_assert(is_same>::value, + "is_same>::value"); + static_assert(is_same>::value, + "is_same>::value"); + static_assert(is_same>::value, + "is_same>::value"); + static_assert(is_same>::value, + "is_same>::value"); + EXPECT_TRUE(offset_3.data() == std::begin(sequence) + 3); + EXPECT_TRUE(offset_4.data() == std::begin(sequence) + 4); + EXPECT_TRUE(offset_5.data() == std::begin(sequence) + 5); + EXPECT_TRUE(offset_6.data() == std::begin(sequence) + 6); + EXPECT_TRUE(offset_3.size() == 6); + EXPECT_TRUE(offset_4.size() == 5); + EXPECT_TRUE(offset_5.size() == 4); + EXPECT_TRUE(offset_6.size() == 3); + + auto subspan_3 = sp_dyn.subspan<3, 2>(); + auto subspan_4 = sp_nine.subspan<4, 2>(); + auto subspan_5 = sp_dyn.subspan(5, 2); + auto subspan_6 = sp_nine.subspan(6, 2); + static_assert(noexcept(sp_dyn.subspan<3, 2>()), + "noexcept(sp_dyn.subspan<3, 2>())"); // strengthened + static_assert(noexcept(sp_nine.subspan<4, 2>()), + "noexcept(sp_nine.subspan<4, 2>())"); // strengthened + static_assert(noexcept(sp_dyn.subspan(5, 2)), + "noexcept(sp_dyn.subspan(5, 2))"); // strengthened + static_assert(noexcept(sp_nine.subspan(6, 2)), + "noexcept(sp_nine.subspan(6, 2))"); // strengthened + static_assert(is_same>::value, + "is_same>::value"); + static_assert(is_same>::value, + "is_same>::value"); + static_assert(is_same>::value, + "is_same>::value"); + static_assert(is_same>::value, + "is_same>::value"); + EXPECT_TRUE(subspan_3.data() == std::begin(sequence) + 3); + EXPECT_TRUE(subspan_4.data() == std::begin(sequence) + 4); + EXPECT_TRUE(subspan_5.data() == std::begin(sequence) + 5); + EXPECT_TRUE(subspan_6.data() == std::begin(sequence) + 6); + EXPECT_TRUE(subspan_3.size() == 2); + EXPECT_TRUE(subspan_4.size() == 2); + EXPECT_TRUE(subspan_5.size() == 2); + EXPECT_TRUE(subspan_6.size() == 2); + + static_assert(noexcept(sp_dyn.size()), "noexcept(sp_dyn.size())"); + static_assert(noexcept(sp_dyn.size_bytes()), "noexcept(sp_dyn.size_bytes())"); + static_assert(noexcept(sp_dyn.empty()), "noexcept(sp_dyn.empty())"); + static_assert(noexcept(sp_dyn[0]), "noexcept(sp_dyn[0])"); // strengthened + static_assert(noexcept(sp_dyn.front()), "noexcept(sp_dyn.front())"); // strengthened + static_assert(noexcept(sp_dyn.back()), "noexcept(sp_dyn.back())"); // strengthened + static_assert(noexcept(sp_dyn.data()), "noexcept(sp_dyn.data())"); + static_assert(noexcept(sp_dyn.begin()), "noexcept(sp_dyn.begin())"); + static_assert(noexcept(sp_dyn.end()), "noexcept(sp_dyn.end())"); + static_assert(noexcept(sp_dyn.cbegin()), "noexcept(sp_dyn.cbegin())"); + static_assert(noexcept(sp_dyn.cend()), "noexcept(sp_dyn.cend())"); + static_assert(noexcept(sp_dyn.rbegin()), "noexcept(sp_dyn.rbegin())"); + static_assert(noexcept(sp_dyn.rend()), "noexcept(sp_dyn.rend())"); + static_assert(noexcept(sp_dyn.crbegin()), "noexcept(sp_dyn.crbegin())"); + static_assert(noexcept(sp_dyn.crend()), "noexcept(sp_dyn.crend())"); + + static_assert(noexcept(sp_nine.size()), "noexcept(sp_nine.size())"); + static_assert(noexcept(sp_nine.size_bytes()), "noexcept(sp_nine.size_bytes())"); + static_assert(noexcept(sp_nine.empty()), "noexcept(sp_nine.empty())"); + static_assert(noexcept(sp_nine[0]), "noexcept(sp_nine[0])"); // strengthened + static_assert(noexcept(sp_nine.front()), "noexcept(sp_nine.front())"); // strengthened + static_assert(noexcept(sp_nine.back()), "noexcept(sp_nine.back())"); // strengthened + static_assert(noexcept(sp_nine.data()), "noexcept(sp_nine.data())"); + static_assert(noexcept(sp_nine.begin()), "noexcept(sp_nine.begin())"); + static_assert(noexcept(sp_nine.end()), "noexcept(sp_nine.end())"); + static_assert(noexcept(sp_nine.cbegin()), "noexcept(sp_nine.cbegin())"); + static_assert(noexcept(sp_nine.cend()), "noexcept(sp_nine.cend())"); + static_assert(noexcept(sp_nine.rbegin()), "noexcept(sp_nine.rbegin())"); + static_assert(noexcept(sp_nine.rend()), "noexcept(sp_nine.rend())"); + static_assert(noexcept(sp_nine.crbegin()), "noexcept(sp_nine.crbegin())"); + static_assert(noexcept(sp_nine.crend()), "noexcept(sp_nine.crend())"); + + EXPECT_TRUE(sp_dyn.size() == 9); + EXPECT_TRUE(sp_nine.size() == 9); + + EXPECT_TRUE(sp_dyn.size_bytes() == 9 * sizeof(int)); + EXPECT_TRUE(sp_nine.size_bytes() == 9 * sizeof(int)); + + EXPECT_TRUE(!sp_dyn.empty()); + EXPECT_TRUE(!sp_nine.empty()); + + EXPECT_TRUE(sp_dyn[0] == 10); + EXPECT_TRUE(sp_nine[0] == 10); + EXPECT_TRUE(sp_dyn[8] == 90); + EXPECT_TRUE(sp_nine[8] == 90); + + EXPECT_TRUE(sp_dyn.front() == 10); + EXPECT_TRUE(sp_nine.front() == 10); + + EXPECT_TRUE(sp_dyn.back() == 90); + EXPECT_TRUE(sp_nine.back() == 90); + + EXPECT_TRUE(&sp_dyn.front() == std::begin(sequence)); + EXPECT_TRUE(&sp_nine.front() == std::begin(sequence)); + EXPECT_TRUE(&sp_dyn[4] == std::begin(sequence) + 4); + EXPECT_TRUE(&sp_nine[4] == std::begin(sequence) + 4); + EXPECT_TRUE(&sp_dyn.back() == std::begin(sequence) + 8); + EXPECT_TRUE(&sp_nine.back() == std::begin(sequence) + 8); + + EXPECT_TRUE(sp_dyn.data() == std::begin(sequence)); + EXPECT_TRUE(sp_nine.data() == std::begin(sequence)); + + EXPECT_TRUE(*sp_dyn.begin() == 10); + EXPECT_TRUE(*sp_nine.begin() == 10); + + EXPECT_TRUE(sp_dyn.end()[-2] == 80); + EXPECT_TRUE(sp_nine.end()[-2] == 80); + + EXPECT_TRUE(*sp_dyn.cbegin() == 10); + EXPECT_TRUE(*sp_nine.cbegin() == 10); + + EXPECT_TRUE(sp_dyn.cend()[-2] == 80); + EXPECT_TRUE(sp_nine.cend()[-2] == 80); + + EXPECT_TRUE(*sp_dyn.rbegin() == 90); + EXPECT_TRUE(*sp_nine.rbegin() == 90); + + EXPECT_TRUE(sp_dyn.rend()[-2] == 20); + EXPECT_TRUE(sp_nine.rend()[-2] == 20); + + EXPECT_TRUE(*sp_dyn.crbegin() == 90); + EXPECT_TRUE(*sp_nine.crbegin() == 90); + + EXPECT_TRUE(sp_dyn.crend()[-2] == 20); + EXPECT_TRUE(sp_nine.crend()[-2] == 20); + + static_assert(is_same::iterator>::value, + "is_same::iterator>::value"); + static_assert(is_same::iterator>::value, + "is_same::iterator>::value"); + static_assert(is_same::iterator>::value, + "is_same::iterator>::value"); + static_assert(is_same::iterator>::value, + "is_same::iterator>::value"); + static_assert(is_same::const_iterator>::value, + "is_same::const_iterator>::value"); + static_assert( + is_same::const_iterator>::value, + "is_same::const_iterator>::value"); + static_assert(is_same::const_iterator>::value, + "is_same::const_iterator>::value"); + static_assert( + is_same::const_iterator>::value, + "is_same::const_iterator>::value"); + static_assert( + is_same::reverse_iterator>::value, + "is_same::reverse_iterator>::value"); + static_assert( + is_same::reverse_iterator>::value, + "is_same::reverse_iterator>::value"); + static_assert(is_same::reverse_iterator>::value, + "is_same::reverse_iterator>::value"); + static_assert( + is_same::reverse_iterator>::value, + "is_same::reverse_iterator>::value"); + static_assert( + is_same::const_reverse_iterator>::value, + "is_same::const_reverse_iterator>::value"); + static_assert( + is_same::const_reverse_iterator>::value, + "is_same::const_reverse_iterator>::value"); + static_assert( + is_same::const_reverse_iterator>::value, + "is_same::const_reverse_iterator>::value"); + static_assert( + is_same::const_reverse_iterator>::value, + "is_same::const_reverse_iterator>::value"); + } + { + int sequence[9]{10, 20, 30, 40, 50, 60, 70, 80, 90}; + + constexpr size_t SizeBytes = sizeof(sequence); + + const gsl::span sp_dyn(sequence); + const gsl::span sp_nine(sequence); + const gsl::span sp_const_dyn(sequence); + const gsl::span sp_const_nine(sequence); + + static_assert(noexcept(as_bytes(sp_dyn)), "noexcept(as_bytes(sp_dyn))"); + static_assert(noexcept(as_bytes(sp_nine)), "noexcept(as_bytes(sp_nine))"); + static_assert(noexcept(as_bytes(sp_const_dyn)), "noexcept(as_bytes(sp_const_dyn))"); + static_assert(noexcept(as_bytes(sp_const_nine)), "noexcept(as_bytes(sp_const_nine))"); + static_assert(noexcept(as_writable_bytes(sp_dyn)), "noexcept(as_writable_bytes(sp_dyn))"); + static_assert(noexcept(as_writable_bytes(sp_nine)), "noexcept(as_writable_bytes(sp_nine))"); + + auto sp_1 = as_bytes(sp_dyn); + auto sp_2 = as_bytes(sp_nine); + auto sp_3 = as_bytes(sp_const_dyn); + auto sp_4 = as_bytes(sp_const_nine); + auto sp_5 = as_writable_bytes(sp_dyn); + auto sp_6 = as_writable_bytes(sp_nine); + + static_assert(is_same>::value, + "is_same>::value"); + static_assert(is_same>::value, + "is_same>::value"); + static_assert(is_same>::value, + "is_same>::value"); + static_assert(is_same>::value, + "is_same>::value"); + static_assert(is_same>::value, + "is_same>::value"); + static_assert(is_same>::value, + "is_same>::value"); + + EXPECT_TRUE(sp_1.data() == reinterpret_cast(begin(sequence))); + EXPECT_TRUE(sp_2.data() == reinterpret_cast(begin(sequence))); + EXPECT_TRUE(sp_3.data() == reinterpret_cast(begin(sequence))); + EXPECT_TRUE(sp_4.data() == reinterpret_cast(begin(sequence))); + EXPECT_TRUE(sp_5.data() == reinterpret_cast(begin(sequence))); + EXPECT_TRUE(sp_6.data() == reinterpret_cast(begin(sequence))); + + EXPECT_TRUE(sp_1.size() == SizeBytes); + EXPECT_TRUE(sp_2.size() == SizeBytes); + EXPECT_TRUE(sp_3.size() == SizeBytes); + EXPECT_TRUE(sp_4.size() == SizeBytes); + EXPECT_TRUE(sp_5.size() == SizeBytes); + EXPECT_TRUE(sp_6.size() == SizeBytes); + } +} + +// assertions for span's definition +static_assert(std::is_same::value, + "gsl::dynamic_extent must be respresented as std::size_t"); +static_assert(gsl::dynamic_extent == static_cast(-1), + "gsl::dynamic_extent must be defined as the max value of std::size_t"); + +static_assert(std::is_same::extent), const std::size_t>::value, + "Ensure that the type of gsl::span::extent is std::size_t"); +static_assert(gsl::span::extent == gsl::dynamic_extent, + "gsl::span::extent should be equivalent to gsl::dynamic_extent"); + +static_assert(std::is_same::extent), const std::size_t>::value, + "Ensure that the type of gsl::span::extent is std::size_t"); +static_assert(gsl::span::extent == 3, "Ensure that span::extent is equal to 3"); + +static_assert(std::is_same::element_type, int>::value, + "span::element_type should be int"); +static_assert(std::is_same::value_type, int>::value, + "span::value_type should be int"); +static_assert(std::is_same::size_type, std::size_t>::value, + "span::size_type should be std::size_t"); +static_assert(std::is_same::difference_type, ptrdiff_t>::value, + "span::difference_type should be std::ptrdiff_t"); +static_assert(std::is_same::pointer, int*>::value, + "span::pointer should be int*"); +static_assert(std::is_same::const_pointer, const int*>::value, + "span::const_pointer should be const int*"); +static_assert(std::is_same::reference, int&>::value, + "span::reference should be int&"); +static_assert(std::is_same::const_reference, const int&>::value, + "span::const_reference should be const int&"); + +static_assert(std::is_same::element_type, int>::value, + "span::element_type should be int"); +static_assert(std::is_same::value_type, int>::value, + "span::value_type should be int"); +static_assert(std::is_same::size_type, std::size_t>::value, + "span::size_type should be std::size_t"); +static_assert(std::is_same::difference_type, ptrdiff_t>::value, + "span::difference_type should be std::ptrdiff_t"); +static_assert(std::is_same::pointer, int*>::value, + "span::pointer should be int*"); +static_assert(std::is_same::const_pointer, const int*>::value, + "span::const_pointer should be const int*"); +static_assert(std::is_same::reference, int&>::value, + "span::reference should be int&"); +static_assert(std::is_same::const_reference, const int&>::value, + "span::const_reference should be const int&"); + +static_assert(std::is_same::element_type, const int>::value, + "span::element_type should be const int"); +static_assert(std::is_same::value_type, int>::value, + "span::value_type should be int"); +static_assert(std::is_same::size_type, std::size_t>::value, + "span::size_type should be size_t"); +static_assert(std::is_same::difference_type, ptrdiff_t>::value, + "span::difference_type should be ptrdiff_t"); +static_assert(std::is_same::pointer, const int*>::value, + "span::pointer should be const int*"); +static_assert(std::is_same::const_pointer, const int*>::value, + "span::const_pointer should be const int*"); +static_assert(std::is_same::reference, const int&>::value, + "span::reference should be const int&"); +static_assert(std::is_same::const_reference, const int&>::value, + "span::const_reference should be const int&"); + +static_assert(std::is_same::element_type, const int>::value, + "span::element_type should be const int"); +static_assert(std::is_same::value_type, int>::value, + "span::value_type should be int"); +static_assert(std::is_same::size_type, std::size_t>::value, + "span::size_type should be size_t"); +static_assert(std::is_same::difference_type, ptrdiff_t>::value, + "span::difference_type should be ptrdiff_t"); +static_assert(std::is_same::pointer, const int*>::value, + "span::pointer should be const int*"); +static_assert(std::is_same::const_pointer, const int*>::value, + "span::const_pointer should be const int*"); +static_assert(std::is_same::reference, const int&>::value, + "span::reference should be const int&"); +static_assert(std::is_same::const_reference, const int&>::value, + "span::const_reference should be const int&"); + +// assertions for span_iterator +static_assert(std::is_same::iterator>::pointer, int*>::value, + "span::iterator's pointer should be int*"); +static_assert( + std::is_same::const_iterator>::pointer, const int*>::value, + "span::const_iterator's pointer should be const int*"); +static_assert( + std::is_same::reverse_iterator, + std::reverse_iterator::iterator>>::value, + "span::reverse_iterator should equal std::reverse_iterator::iterator>"); +static_assert(std::is_same::const_reverse_iterator, + std::reverse_iterator::const_iterator>>::value, + "span::const_reverse_iterator should equal " + "std::reverse_iterator::const_iterator>"); + +static_assert(std::is_same::iterator>::pointer, int*>::value, + "span::iterator's pointer should be int*"); +static_assert(std::is_same::const_iterator>::pointer, + const int*>::value, + "span::const_iterator's pointer should be const int*"); +static_assert( + std::is_same::reverse_iterator, + std::reverse_iterator::iterator>>::value, + "span::reverse_iterator should equal std::reverse_iterator::iterator>"); +static_assert(std::is_same::const_reverse_iterator, + std::reverse_iterator::const_iterator>>::value, + "span::const_reverse_iterator should equal std::reverse_iterator::const_iterator>"); + +static_assert( + std::is_same::iterator>::pointer, const int*>::value, + "span::iterator's pointer should be int*"); +static_assert(std::is_same::const_iterator>::pointer, + const int*>::value, + "span::const_iterator's pointer should be const int*"); +static_assert(std::is_same::reverse_iterator, + std::reverse_iterator::iterator>>::value, + "span::reverse_iterator should equal std::reverse_iterator::iterator>"); +static_assert(std::is_same::const_reverse_iterator, + std::reverse_iterator::const_iterator>>::value, + "span::const_reverse_iterator should equal " + "std::reverse_iterator::const_iterator>"); + +static_assert(std::is_same::iterator>::pointer, + const int*>::value, + "span::iterator's pointer should be int*"); +static_assert(std::is_same::const_iterator>::pointer, + const int*>::value, + "span::const_iterator's pointer should be const int*"); +static_assert(std::is_same::reverse_iterator, + std::reverse_iterator::iterator>>::value, + "span::reverse_iterator should equal std::reverse_iterator::iterator>"); +static_assert(std::is_same::const_reverse_iterator, + std::reverse_iterator::const_iterator>>::value, + "span::const_reverse_iterator should equal " + "std::reverse_iterator::const_iterator>"); + +// copyability assertions +static_assert(std::is_trivially_copyable>::value, + "span should be trivially copyable"); +static_assert(std::is_trivially_copyable::iterator>::value, + "span::iterator should be trivially copyable"); +static_assert(std::is_trivially_copyable::const_iterator>::value, + "span::const_iterator should be trivially copyable"); + +static_assert(std::is_trivially_copyable>::value, + "span should be trivially copyable"); +static_assert(std::is_trivially_copyable::iterator>::value, + "span::iterator should be trivially copyable"); +static_assert(std::is_trivially_copyable::const_iterator>::value, + "span::const_iterator should be trivially copyable"); + +static_assert(std::is_trivially_copyable>::value, + "span should be trivially copyable"); +static_assert(std::is_trivially_copyable::iterator>::value, + "span::iterator should be trivially copyable"); +static_assert(std::is_trivially_copyable::const_iterator>::value, + "span::const_iterator should be trivially copyable"); + +static_assert(std::is_trivially_copyable>::value, + "span should be trivially copyable"); +static_assert(std::is_trivially_copyable::iterator>::value, + "span::iterator should be trivially copyable"); +static_assert(std::is_trivially_copyable::const_iterator>::value, + "span::const_iterator should be trivially copyable"); + +// nothrow constructible assertions +static_assert(std::is_nothrow_constructible, int*, std::size_t>::value, + "std::is_nothrow_constructible, int*, std::size_t>"); +static_assert(std::is_nothrow_constructible, int*, std::uint16_t>::value, + "std::is_nothrow_constructible, int*, std::uint16_t>"); +static_assert(std::is_nothrow_constructible, int*, int*>::value, + "std::is_nothrow_constructible, int*, int*>"); +static_assert(std::is_nothrow_constructible, int (&)[3]>::value, + "std::is_nothrow_constructible, int(&)[3]>"); +static_assert(std::is_nothrow_constructible, const gsl::span&>::value, + "std::is_nothrow_constructible, const gsl::span&>"); +static_assert(std::is_nothrow_constructible, const gsl::span&>::value, + "std::is_nothrow_constructible, const gsl::span&>"); +static_assert(std::is_nothrow_constructible, const gsl::span&>::value, + "std::is_nothrow_constructible, const gsl::span&>"); +static_assert(std::is_nothrow_constructible, std::array&>::value, + "std::is_nothrow_constructible, std::array&>"); + +static_assert(std::is_nothrow_constructible, int*, std::size_t>::value, + "std::is_nothrow_constructible, int*, std::size_t>"); +static_assert(std::is_nothrow_constructible, int*, std::uint16_t>::value, + "std::is_nothrow_constructible, int*, std::uint16_t>"); +static_assert(std::is_nothrow_constructible, int*, int*>::value, + "std::is_nothrow_constructible, int*, int*>"); +static_assert(std::is_nothrow_constructible, int (&)[3]>::value, + "std::is_nothrow_constructible, int(&)[3]>"); +static_assert(std::is_nothrow_constructible, const gsl::span&>::value, + "std::is_nothrow_constructible, const gsl::span&>"); +static_assert(std::is_nothrow_constructible, std::array&>::value, + "std::is_nothrow_constructible, std::array&>"); + +static_assert(std::is_nothrow_constructible, int*, std::size_t>::value, + "std::is_nothrow_constructible, int*, std::size_t>"); +static_assert(std::is_nothrow_constructible, int*, int*>::value, + "std::is_nothrow_constructible, int*, int*>"); +static_assert(std::is_nothrow_constructible, int*, const int*>::value, + "std::is_nothrow_constructible, int*, const int*>"); +static_assert(std::is_nothrow_constructible, int (&)[3]>::value, + "std::is_nothrow_constructible, int(&)[3]>"); +static_assert(std::is_nothrow_constructible, const int*, int*>::value, + "std::is_nothrow_constructible, const int*, int*>"); +static_assert(std::is_nothrow_constructible, const int*, const int*>::value, + "std::is_nothrow_constructible, const int*, const int*>"); +static_assert(std::is_nothrow_constructible, const int*, std::size_t>::value, + "std::is_nothrow_constructible, const int*, std::size_t>"); +static_assert(std::is_nothrow_constructible, const int (&)[3]>::value, + "std::is_nothrow_constructible, const int(&)[3]>"); +static_assert(std::is_nothrow_constructible, const gsl::span&>::value, + "std::is_nothrow_constructible, const gsl::span&>"); +static_assert(std::is_nothrow_constructible, const gsl::span&>::value, + "std::is_nothrow_constructible, const gsl::span&>"); +static_assert( + std::is_nothrow_constructible, const gsl::span&>::value, + "std::is_nothrow_constructible, const gsl::span&>"); +static_assert( + std::is_nothrow_constructible, const gsl::span&>::value, + "std::is_nothrow_constructible, const gsl::span&>"); +static_assert( + std::is_nothrow_constructible, const gsl::span&>::value, + "std::is_nothrow_constructible, const gsl::span&>"); +static_assert( + std::is_nothrow_constructible, const gsl::span&>::value, + "std::is_nothrow_constructible, const gsl::span&>"); +static_assert(std::is_nothrow_constructible, std::array&>::value, + "std::is_nothrow_constructible, std::array&>"); +static_assert(std::is_nothrow_constructible, const std::array&>::value, + "std::is_nothrow_constructible, const std::array&>"); + +static_assert( + std::is_nothrow_constructible, const gsl::span&>::value, + "std::is_nothrow_constructible, const gsl::span&>"); +static_assert( + std::is_nothrow_constructible, const gsl::span&>::value, + "std::is_nothrow_constructible, const gsl::span&>"); + +static_assert(std::is_nothrow_constructible, Base (&)[3]>::value, + "std::is_nothrow_constructible, Base(&)[3]>"); +static_assert(std::is_nothrow_constructible, const gsl::span&>::value, + "std::is_nothrow_constructible, const gsl::span&>"); +static_assert(std::is_nothrow_constructible, const gsl::span&>::value, + "std::is_nothrow_constructible, const gsl::span&>"); +static_assert(std::is_nothrow_constructible, std::array&>::value, + "std::is_nothrow_constructible, std::array&>"); + +static_assert(std::is_nothrow_constructible, Base (&)[3]>::value, + "std::is_nothrow_constructible, Base(&)[3]>"); +static_assert(std::is_nothrow_constructible, const gsl::span&>::value, + "std::is_nothrow_constructible, const gsl::span&>"); +static_assert(std::is_nothrow_constructible, std::array&>::value, + "std::is_nothrow_constructible, std::array&>"); + +static_assert(std::is_nothrow_constructible, Base (&)[3]>::value, + "std::is_nothrow_constructible, Base(&)[3]>"); +static_assert(std::is_nothrow_constructible, const Base (&)[3]>::value, + "std::is_nothrow_constructible, const Base(&)[3]>"); +static_assert(std::is_nothrow_constructible, const gsl::span&>::value, + "std::is_nothrow_constructible, const gsl::span&>"); +static_assert( + std::is_nothrow_constructible, const gsl::span&>::value, + "std::is_nothrow_constructible, const gsl::span&>"); +static_assert( + std::is_nothrow_constructible, const gsl::span&>::value, + "std::is_nothrow_constructible, const gsl::span&>"); +static_assert( + std::is_nothrow_constructible, const gsl::span&>::value, + "std::is_nothrow_constructible, const gsl::span&>"); +static_assert(std::is_nothrow_constructible, std::array&>::value, + "std::is_nothrow_constructible, std::array&>"); +static_assert( + std::is_nothrow_constructible, const std::array&>::value, + "std::is_nothrow_constructible, const std::array&>"); + +static_assert( + std::is_nothrow_constructible, const gsl::span&>::value, + "std::is_nothrow_constructible, const gsl::span&>"); +static_assert( + std::is_nothrow_constructible, const gsl::span&>::value, + "std::is_nothrow_constructible, const gsl::span&>"); + +// non-constructible assertions +static_assert(!std::is_constructible, const int*, int*>::value, + "!std::is_constructible, const int*, int*>"); +static_assert(!std::is_constructible, const int*, const int*>::value, + "!std::is_constructible, const int*, const int*>"); +static_assert(!std::is_constructible, const int*, double*>::value, + "!std::is_constructible, const int*, double*>"); +static_assert(!std::is_constructible, const int*, std::size_t>::value, + "!std::is_constructible, const int*, std::size_t>"); +static_assert(!std::is_constructible, const int (&)[3]>::value, + "!std::is_constructible, const int(&)[3]>"); +static_assert(!std::is_constructible, double*, int*>::value, + "!std::is_constructible, double*, int*>"); +static_assert(!std::is_constructible, double*, const int*>::value, + "!std::is_constructible, double*, const int*>"); +static_assert(!std::is_constructible, double*, double*>::value, + "!std::is_constructible, double*, double*>"); +static_assert(!std::is_constructible, double*, std::size_t>::value, + "!std::is_constructible, double*, std::size_t>"); +static_assert(!std::is_constructible, double (&)[3]>::value, + "!std::is_constructible, double(&)[3]>"); +static_assert(!std::is_constructible, int*, double*>::value, + "!std::is_constructible, int*, double*>"); +static_assert(!std::is_constructible, std::size_t, int*>::value, + "!std::is_constructible, std::size_t, int*>"); +static_assert(!std::is_constructible, std::size_t, std::size_t>::value, + "!std::is_constructible, std::size_t, std::size_t>"); +static_assert(!std::is_constructible, const gsl::span&>::value, + "!std::is_constructible, const gsl::span&>"); +static_assert(!std::is_constructible, const gsl::span&>::value, + "!std::is_constructible, const gsl::span&>"); +static_assert(!std::is_constructible, const gsl::span&>::value, + "!std::is_constructible, const gsl::span&>"); +static_assert(!std::is_constructible, const gsl::span&>::value, + "!std::is_constructible, const gsl::span&>"); +static_assert(!std::is_constructible, std::array&>::value, + "!std::is_constructible, std::array&>"); +static_assert(!std::is_constructible, const std::array&>::value, + "!std::is_constructible, const std::array&>"); + +static_assert(!std::is_constructible, int*, double*>::value, + "!std::is_constructible, int*, double*>"); +static_assert(!std::is_constructible, int (&)[500]>::value, + "!std::is_constructible, int(&)[500]>"); +static_assert(!std::is_constructible, const int*, int*>::value, + "!std::is_constructible, const int*, int*>"); +static_assert(!std::is_constructible, const int*, const int*>::value, + "!std::is_constructible, const int*, const int*>"); +static_assert(!std::is_constructible, const int*, std::size_t>::value, + "!std::is_constructible, const int*, std::size_t>"); +static_assert(!std::is_constructible, const int*, double*>::value, + "!std::is_constructible, const int*, double*>"); +static_assert(!std::is_constructible, const int (&)[3]>::value, + "!std::is_constructible, const int(&)[3]>"); +static_assert(!std::is_constructible, double*, std::size_t>::value, + "!std::is_constructible, double*, std::size_t>"); +static_assert(!std::is_constructible, double*, int*>::value, + "!std::is_constructible, double*, int*>"); +static_assert(!std::is_constructible, double*, const int*>::value, + "!std::is_constructible, double*, const int*>"); +static_assert(!std::is_constructible, double*, double*>::value, + "!std::is_constructible, double*, double*>"); +static_assert(!std::is_constructible, double (&)[3]>::value, + "!std::is_constructible, double(&)[3]>"); + +static_assert(!std::is_constructible, std::size_t, int*>::value, + "!std::is_constructible, std::size_t, int*>"); +static_assert(!std::is_constructible, std::size_t, std::size_t>::value, + "!std::is_constructible, std::size_t, std::size_t>"); +static_assert(!std::is_constructible, std::array&>::value, + "!std::is_constructible, std::array&>"); +static_assert(!std::is_constructible, std::array&>::value, + "!std::is_constructible, std::array&>"); +static_assert(!std::is_constructible, const std::array&>::value, + "!std::is_constructible, const std::array&>"); +static_assert(!std::is_constructible, const gsl::span&>::value, + "!std::is_constructible, const gsl::span&>"); +static_assert(!std::is_constructible, const gsl::span&>::value, + "!std::is_constructible, const gsl::span&>"); +static_assert(!std::is_constructible, const gsl::span&>::value, + "!std::is_constructible, const gsl::span&>"); +static_assert(!std::is_constructible, const gsl::span&>::value, + "!std::is_constructible, const gsl::span&>"); +static_assert(!std::is_constructible, const gsl::span&>::value, + "!std::is_constructible, const gsl::span&>"); +static_assert(!std::is_constructible, const gsl::span&>::value, + "!std::is_constructible, const gsl::span&>"); + +static_assert(!std::is_constructible, double (&)[3]>::value, + "!std::is_constructible, double(&)[3]>"); +static_assert(!std::is_constructible, std::array&>::value, + "!std::is_constructible, std::array&>"); +static_assert(!std::is_constructible, const gsl::span&>::value, + "!std::is_constructible, const gsl::span&>"); + +static_assert(!std::is_constructible, const gsl::span&>::value, + "!std::is_constructible, const gsl::span&>"); +static_assert(!std::is_constructible, const gsl::span&>::value, + "!std::is_constructible, const gsl::span&>"); +static_assert(!std::is_constructible, const gsl::span&>::value, + "!std::is_constructible, const gsl::span&>"); +static_assert( + !std::is_constructible, const gsl::span&>::value, + "!std::is_constructible, const gsl::span&>"); +static_assert(!std::is_constructible, const gsl::span&>::value, + "!std::is_constructible, const gsl::span&>"); + +static_assert(!std::is_constructible, Derived (&)[3]>::value, + "!std::is_constructible, Derived(&)[3]>"); +static_assert(!std::is_constructible, std::array&>::value, + "!std::is_constructible, std::array&>"); +static_assert(!std::is_constructible, std::vector&>::value, + "!std::is_constructible, std::vector&>"); +static_assert(!std::is_constructible, const gsl::span&>::value, + "!std::is_constructible, const gsl::span&>"); +static_assert(!std::is_constructible, const gsl::span&>::value, + "!std::is_constructible, const gsl::span&>"); + +static_assert(!std::is_constructible, const gsl::span&>::value, + "!std::is_constructible, const gsl::span&>"); +static_assert(!std::is_constructible, Derived (&)[3]>::value, + "!std::is_constructible, Derived(&)[3]>"); +static_assert(!std::is_constructible, std::array&>::value, + "!std::is_constructible, std::array&>"); + +static_assert(!std::is_constructible, Derived (&)[3]>::value, + "!std::is_constructible, Derived(&)[3]>"); +static_assert(!std::is_constructible, const Derived (&)[3]>::value, + "!std::is_constructible, const Derived(&)[3]>"); +static_assert(!std::is_constructible, std::array&>::value, + "!std::is_constructible, std::array&>"); +static_assert(!std::is_constructible, const std::array&>::value, + "!std::is_constructible, const std::array&>"); +static_assert(!std::is_constructible, const gsl::span&>::value, + "!std::is_constructible, const gsl::span&>"); +static_assert(!std::is_constructible, const gsl::span&>::value, + "!std::is_constructible, const gsl::span&>"); +static_assert(!std::is_constructible, const gsl::span&>::value, + "!std::is_constructible, const gsl::span&>"); +static_assert( + !std::is_constructible, const gsl::span&>::value, + "!std::is_constructible, const gsl::span&>"); + +static_assert(!std::is_constructible, const gsl::span&>::value, + "!std::is_constructible, const gsl::span&>"); +static_assert( + !std::is_constructible, const gsl::span&>::value, + "!std::is_constructible, const gsl::span&>"); + +static_assert(!std::is_constructible, std::array&>::value, + "!std::is_constructible, std::array&>"); +static_assert(!std::is_constructible, const std::array&>::value, + "!std::is_constructible, const std::array&>"); + +// no throw copy constructor +static_assert(std::is_nothrow_copy_constructible>::value, + "std::is_nothrow_copy_constructible>"); +static_assert(std::is_nothrow_copy_constructible>::value, + "std::is_nothrow_copy_constructible>"); +static_assert(std::is_nothrow_copy_constructible>::value, + "std::is_nothrow_copy_constructible>"); +static_assert(std::is_nothrow_copy_constructible>::value, + "std::is_nothrow_copy_constructible>"); + +// no throw copy assignment +static_assert(std::is_nothrow_copy_assignable>::value, + "std::is_nothrow_copy_assignable>"); +static_assert(std::is_nothrow_copy_assignable>::value, + "std::is_nothrow_copy_assignable>"); +static_assert(std::is_nothrow_copy_assignable>::value, + "std::is_nothrow_copy_assignable>"); +static_assert(std::is_nothrow_copy_assignable>::value, + "std::is_nothrow_copy_assignable>"); + +// no throw destruction +static_assert(std::is_nothrow_destructible>::value, + "std::is_nothrow_destructible>"); +static_assert(std::is_nothrow_destructible>::value, + "std::is_nothrow_destructible>"); +static_assert(std::is_nothrow_destructible>::value, + "std::is_nothrow_destructible>"); + +// conversions +static_assert(std::is_convertible>::value, + "std::is_convertible>"); +static_assert(std::is_convertible>::value, + "std::is_convertible>"); +static_assert(std::is_convertible>::value, + "std::is_convertible>"); + +static_assert(std::is_convertible>::value, + "std::is_convertible>"); + +static_assert(std::is_convertible&, gsl::span>::value, + "std::is_convertible&, gsl::span>"); +static_assert(std::is_convertible&, gsl::span>::value, + "std::is_convertible&, gsl::span>"); + +static_assert(std::is_convertible&, gsl::span>::value, + "std::is_convertible&, gsl::span>"); +static_assert(std::is_convertible&, gsl::span>::value, + "std::is_convertible&, gsl::span>"); +static_assert(std::is_convertible&, gsl::span>::value, + "std::is_convertible&, gsl::span>"); +static_assert(std::is_convertible&, gsl::span>::value, + "std::is_convertible&, gsl::span>"); +static_assert(std::is_convertible&, gsl::span>::value, + "std::is_convertible&, gsl::span>"); +static_assert(std::is_convertible&, gsl::span>::value, + "std::is_convertible&, gsl::span>"); + +static_assert(std::is_convertible&, gsl::span>::value, + "std::is_convertible&, gsl::span>"); + +static_assert(std::is_convertible&, gsl::span>::value, + "std::is_convertible&, gsl::span>"); +static_assert(std::is_convertible&, gsl::span>::value, + "std::is_convertible&, gsl::span>"); +static_assert(std::is_convertible&, gsl::span>::value, + "std::is_convertible&, gsl::span>"); + +static_assert(std::is_convertible&, gsl::span>::value, + "std::is_convertible&, gsl::span>"); +static_assert(std::is_convertible&, gsl::span>::value, + "std::is_convertible&, gsl::span>"); +static_assert(std::is_convertible&, gsl::span>::value, + "std::is_convertible&, gsl::span>"); + +static_assert(std::is_convertible&, gsl::span>::value, + "std::is_convertible&, gsl::span>"); + + +#if __cplusplus >= 201703l +template +static constexpr bool AsWritableBytesCompilesFor = false; + +template +static constexpr bool AsWritableBytesCompilesFor()))>> = + true; + +static_assert(AsWritableBytesCompilesFor>, + "AsWritableBytesCompilesFor>"); +static_assert(AsWritableBytesCompilesFor>, + "AsWritableBytesCompilesFor>"); +static_assert(!AsWritableBytesCompilesFor>, + "!AsWritableBytesCompilesFor>"); +static_assert(!AsWritableBytesCompilesFor>, + "!AsWritableBytesCompilesFor>"); +#endif // __cplusplus >= 201703l diff --git a/tests/span_ext_tests.cpp b/tests/span_ext_tests.cpp new file mode 100644 index 0000000..bd256a8 --- /dev/null +++ b/tests/span_ext_tests.cpp @@ -0,0 +1,360 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// 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 + +#include // for narrow_cast, at +#include // for operator==, operator!=, make_span + +#include // for array +#include // for cerr +#include // for vector + +using namespace std; +using namespace gsl; + +namespace +{ +static constexpr char deathstring[] = "Expected Death"; +} // namespace + +TEST(span_ext_test, make_span_from_pointer_length_constructor) +{ + std::set_terminate([] { + std::cerr << "Expected Death. from_pointer_length_constructor"; + std::abort(); + }); + int arr[4] = {1, 2, 3, 4}; + + { + auto s = make_span(&arr[0], 2); + EXPECT_TRUE(s.size() == 2); + EXPECT_TRUE(s.data() == &arr[0]); + EXPECT_TRUE(s[0] == 1); + EXPECT_TRUE(s[1] == 2); + } + + { + int* p = nullptr; + auto s = make_span(p, narrow_cast::size_type>(0)); + EXPECT_TRUE(s.size() == 0); + EXPECT_TRUE(s.data() == nullptr); + } + + { + int* p = nullptr; + auto workaround_macro = [=]() { make_span(p, 2); }; + EXPECT_DEATH(workaround_macro(), deathstring); + } +} + +TEST(span_ext_test, make_span_from_pointer_pointer_construction) +{ + int arr[4] = {1, 2, 3, 4}; + + { + auto s = make_span(&arr[0], &arr[2]); + EXPECT_TRUE(s.size() == 2); + EXPECT_TRUE(s.data() == &arr[0]); + EXPECT_TRUE(s[0] == 1); + EXPECT_TRUE(s[1] == 2); + } + + { + auto s = make_span(&arr[0], &arr[0]); + EXPECT_TRUE(s.size() == 0); + EXPECT_TRUE(s.data() == &arr[0]); + } + + { + int* p = nullptr; + auto s = make_span(p, p); + EXPECT_TRUE(s.size() == 0); + EXPECT_TRUE(s.data() == nullptr); + } +} + +TEST(span_ext_test, make_span_from_array_constructor) + { + int arr[5] = {1, 2, 3, 4, 5}; + int arr2d[2][3] = {1, 2, 3, 4, 5, 6}; + int arr3d[2][3][2] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; + + { + const auto s = make_span(arr); + EXPECT_TRUE(s.size() == 5); + EXPECT_TRUE(s.data() == std::addressof(arr[0])); + } + + { + const auto s = make_span(std::addressof(arr2d[0]), 1); + EXPECT_TRUE(s.size() == 1); + EXPECT_TRUE(s.data() == std::addressof(arr2d[0])); + } + + { + const auto s = make_span(std::addressof(arr3d[0]), 1); + EXPECT_TRUE(s.size() == 1); + EXPECT_TRUE(s.data() == std::addressof(arr3d[0])); + } + } + + TEST(span_ext_test, make_span_from_dynamic_array_constructor) + { + double(*arr)[3][4] = new double[100][3][4]; + + { + auto s = make_span(&arr[0][0][0], 10); + EXPECT_TRUE(s.size() == 10); + EXPECT_TRUE(s.data() == &arr[0][0][0]); + } + + delete[] arr; + } + + TEST(span_ext_test, make_span_from_std_array_constructor) + { + std::array arr = {1, 2, 3, 4}; + + { + auto s = make_span(arr); + EXPECT_TRUE(s.size() == arr.size()); + EXPECT_TRUE(s.data() == arr.data()); + } + + // This test checks for the bug found in gcc 6.1, 6.2, 6.3, 6.4, 6.5 7.1, 7.2, 7.3 - issue #590 + { + span s1 = make_span(arr); + + static span s2; + s2 = s1; + + #if defined(__GNUC__) && __GNUC__ == 6 && (__GNUC_MINOR__ == 4 || __GNUC_MINOR__ == 5) && \ + __GNUC_PATCHLEVEL__ == 0 && defined(__OPTIMIZE__) + // Known to be broken in gcc 6.4 and 6.5 with optimizations + // Issue in gcc: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83116 + EXPECT_TRUE(s1.size() == 4); + EXPECT_TRUE(s2.size() == 0); + #else + EXPECT_TRUE(s1.size() == s2.size()); + #endif + } + } + + TEST(span_ext_test, make_span_from_const_std_array_constructor) + { + const std::array arr = {1, 2, 3, 4}; + + { + auto s = make_span(arr); + EXPECT_TRUE(s.size() == arr.size()); + EXPECT_TRUE(s.data() == arr.data()); + } + } + + TEST(span_ext_test, make_span_from_std_array_const_constructor) + { + std::array arr = {1, 2, 3, 4}; + + { + auto s = make_span(arr); + EXPECT_TRUE(s.size() == arr.size()); + EXPECT_TRUE(s.data() == arr.data()); + } + } + + TEST(span_ext_test, make_span_from_container_constructor) + { + std::vector v = {1, 2, 3}; + const std::vector cv = v; + + { + auto s = make_span(v); + EXPECT_TRUE(s.size() == v.size()); + EXPECT_TRUE(s.data() == v.data()); + + auto cs = make_span(cv); + EXPECT_TRUE(cs.size() == cv.size()); + EXPECT_TRUE(cs.data() == cv.data()); + } + } + + TEST(span_test, interop_with_gsl_at) + { + int arr[5] = {1, 2, 3, 4, 5}; + span s{arr}; + EXPECT_TRUE(at(s, 0) == 1); + EXPECT_TRUE(at(s, 1) == 2); + } + + TEST(span_ext_test, iterator_free_functions) + { + int a[] = {1, 2, 3, 4}; + span s{a}; + + EXPECT_TRUE((std::is_same::value)); + EXPECT_TRUE((std::is_same::value)); + + EXPECT_TRUE((std::is_same::value)); + EXPECT_TRUE((std::is_same::value)); + + EXPECT_TRUE((std::is_same::value)); + EXPECT_TRUE((std::is_same::value)); + + EXPECT_TRUE((std::is_same::value)); + EXPECT_TRUE((std::is_same::value)); + + EXPECT_TRUE(s.begin() == begin(s)); + EXPECT_TRUE(s.end() == end(s)); + + EXPECT_TRUE(s.cbegin() == cbegin(s)); + EXPECT_TRUE(s.cend() == cend(s)); + + EXPECT_TRUE(s.rbegin() == rbegin(s)); + EXPECT_TRUE(s.rend() == rend(s)); + + EXPECT_TRUE(s.crbegin() == crbegin(s)); + EXPECT_TRUE(s.crend() == crend(s)); + } + + TEST(span_ext_test, ssize_free_function) + { + int a[] = {1, 2, 3, 4}; + span s{a}; + + EXPECT_FALSE((std::is_same::value)); + EXPECT_TRUE(s.size() == static_cast(ssize(s))); + } + + TEST(span_ext_test, comparison_operators) + { + { + span s1; + span s2; + EXPECT_TRUE(s1 == s2); + EXPECT_FALSE(s1 != s2); + EXPECT_FALSE(s1 < s2); + EXPECT_TRUE(s1 <= s2); + EXPECT_FALSE(s1 > s2); + EXPECT_TRUE(s1 >= s2); + EXPECT_TRUE(s2 == s1); + EXPECT_FALSE(s2 != s1); + EXPECT_FALSE(s2 != s1); + EXPECT_TRUE(s2 <= s1); + EXPECT_FALSE(s2 > s1); + EXPECT_TRUE(s2 >= s1); + } + + { + int arr[] = {2, 1}; + span s1 = arr; + span s2 = arr; + + EXPECT_TRUE(s1 == s2); + EXPECT_FALSE(s1 != s2); + EXPECT_FALSE(s1 < s2); + EXPECT_TRUE(s1 <= s2); + EXPECT_FALSE(s1 > s2); + EXPECT_TRUE(s1 >= s2); + EXPECT_TRUE(s2 == s1); + EXPECT_FALSE(s2 != s1); + EXPECT_FALSE(s2 < s1); + EXPECT_TRUE(s2 <= s1); + EXPECT_FALSE(s2 > s1); + EXPECT_TRUE(s2 >= s1); + } + + { + int arr[] = {2, 1}; // bigger + + span s1; + span s2 = arr; + + EXPECT_TRUE(s1 != s2); + EXPECT_TRUE(s2 != s1); + EXPECT_FALSE(s1 == s2); + EXPECT_FALSE(s2 == s1); + EXPECT_TRUE(s1 < s2); + EXPECT_FALSE(s2 < s1); + EXPECT_TRUE(s1 <= s2); + EXPECT_FALSE(s2 <= s1); + EXPECT_TRUE(s2 > s1); + EXPECT_FALSE(s1 > s2); + EXPECT_TRUE(s2 >= s1); + EXPECT_FALSE(s1 >= s2); + } + + { + int arr1[] = {1, 2}; + int arr2[] = {1, 2}; + span s1 = arr1; + span s2 = arr2; + + EXPECT_TRUE(s1 == s2); + EXPECT_FALSE(s1 != s2); + EXPECT_FALSE(s1 < s2); + EXPECT_TRUE(s1 <= s2); + EXPECT_FALSE(s1 > s2); + EXPECT_TRUE(s1 >= s2); + EXPECT_TRUE(s2 == s1); + EXPECT_FALSE(s2 != s1); + EXPECT_FALSE(s2 < s1); + EXPECT_TRUE(s2 <= s1); + EXPECT_FALSE(s2 > s1); + EXPECT_TRUE(s2 >= s1); + } + + { + int arr[] = {1, 2, 3}; + + span s1 = {&arr[0], 2}; // shorter + span s2 = arr; // longer + + EXPECT_TRUE(s1 != s2); + EXPECT_TRUE(s2 != s1); + EXPECT_FALSE(s1 == s2); + EXPECT_FALSE(s2 == s1); + EXPECT_TRUE(s1 < s2); + EXPECT_FALSE(s2 < s1); + EXPECT_TRUE(s1 <= s2); + EXPECT_FALSE(s2 <= s1); + EXPECT_TRUE(s2 > s1); + EXPECT_FALSE(s1 > s2); + EXPECT_TRUE(s2 >= s1); + EXPECT_FALSE(s1 >= s2); + } + + { + int arr1[] = {1, 2}; // smaller + int arr2[] = {2, 1}; // bigger + + span s1 = arr1; + span s2 = arr2; + + EXPECT_TRUE(s1 != s2); + EXPECT_TRUE(s2 != s1); + EXPECT_FALSE(s1 == s2); + EXPECT_FALSE(s2 == s1); + EXPECT_TRUE(s1 < s2); + EXPECT_FALSE(s2 < s1); + EXPECT_TRUE(s1 <= s2); + EXPECT_FALSE(s2 <= s1); + EXPECT_TRUE(s2 > s1); + EXPECT_FALSE(s1 > s2); + EXPECT_TRUE(s2 >= s1); + EXPECT_FALSE(s1 >= s2); + } + } diff --git a/tests/span_tests.cpp b/tests/span_tests.cpp index 28c97f5..689fff9 100644 --- a/tests/span_tests.cpp +++ b/tests/span_tests.cpp @@ -14,27 +14,6 @@ // /////////////////////////////////////////////////////////////////////////////// -#ifdef _MSC_VER -// blanket turn off warnings from CppCoreCheck from catch -// so people aren't annoyed by them when running the tool. -#pragma warning(disable : 26440 26426 26497 4189 4996) -#endif - -#if __clang__ || __GNUC__ -//disable warnings from gtest -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wundef" -#pragma GCC diagnostic ignored "-Wunused-variable" -#pragma GCC diagnostic ignored "-Wdeprecated-declarations" -#endif // __clang__ || __GNUC__ - -#if __clang__ -#pragma GCC diagnostic ignored "-Wglobal-constructors" -#pragma GCC diagnostic ignored "-Wused-but-marked-unused" -#pragma GCC diagnostic ignored "-Wcovered-switch-default" -#pragma GCC diagnostic ignored "-Winconsistent-missing-destructor-override" -#endif // __clang__ - #include #include // for byte @@ -46,15 +25,11 @@ #include // for reverse_iterator, operator-, operator== #include // for unique_ptr, shared_ptr, make_unique, allo... #include // for match_results, sub_match, match_results<>... -#include // for ptrdiff_t +#include // for ptrdiff_t #include // for string #include // for integral_constant<>::value, is_default_co... #include // for vector - -namespace gsl -{ -struct fail_fast; -} // namespace gsl +#include using namespace std; using namespace gsl; @@ -131,17 +106,17 @@ TEST(span_test, from_nullptr_size_constructor) std::abort(); }); { - span s{nullptr, narrow_cast::index_type>(0)}; + span s{nullptr, narrow_cast::size_type>(0)}; EXPECT_TRUE(s.size() == 0); EXPECT_TRUE(s.data() == nullptr); - span cs{nullptr, narrow_cast::index_type>(0)}; + span cs{nullptr, narrow_cast::size_type>(0)}; EXPECT_TRUE(cs.size() == 0); EXPECT_TRUE(cs.data() == nullptr); } { auto workaround_macro = []() { - const span s{nullptr, narrow_cast::index_type>(0)}; + const span s{nullptr, narrow_cast::size_type>(0)}; }; EXPECT_DEATH(workaround_macro(), deathstring); } @@ -160,11 +135,11 @@ TEST(span_test, from_nullptr_size_constructor) EXPECT_DEATH(const_workaround_macro(), deathstring); } { - span s{nullptr, narrow_cast::index_type>(0)}; + span s{nullptr, narrow_cast::size_type>(0)}; EXPECT_TRUE(s.size() == 0); EXPECT_TRUE(s.data() == nullptr); - span cs{nullptr, narrow_cast::index_type>(0)}; + span cs{nullptr, narrow_cast::size_type>(0)}; EXPECT_TRUE(cs.size() == 0); EXPECT_TRUE(cs.data() == nullptr); } @@ -182,29 +157,21 @@ TEST(span_test, from_pointer_length_constructor) for (int i = 0; i < 4; ++i) { { - span s = {&arr[0], i}; - EXPECT_TRUE(s.size() == i); + span s = {&arr[0], narrow_cast(i)}; + EXPECT_TRUE(s.size() == narrow_cast(i)); EXPECT_TRUE(s.data() == &arr[0]); EXPECT_TRUE(s.empty() == (i == 0)); for (int j = 0; j < i; ++j) - { - EXPECT_TRUE(arr[j] == s[j]); - EXPECT_TRUE(arr[j] == s.at(j)); - EXPECT_TRUE(arr[j] == s(j)); - } + EXPECT_TRUE(arr[j] == s[narrow_cast(j)]); } { - span s = {&arr[i], 4 - narrow_cast(i)}; - EXPECT_TRUE(s.size() == 4 - i); + span s = {&arr[i], 4 - narrow_cast(i)}; + EXPECT_TRUE(s.size() == 4 - narrow_cast(i)); EXPECT_TRUE(s.data() == &arr[i]); EXPECT_TRUE(s.empty() == ((4 - i) == 0)); for (int j = 0; j < 4 - i; ++j) - { - EXPECT_TRUE(arr[j + i] == s[j]); - EXPECT_TRUE(arr[j + i] == s.at(j)); - EXPECT_TRUE(arr[j + i] == s(j)); - } + EXPECT_TRUE(arr[j + i] == s[narrow_cast(j)]); } } } @@ -219,7 +186,7 @@ TEST(span_test, from_pointer_length_constructor) { int* p = nullptr; - span s{p, narrow_cast::index_type>(0)}; + span s{p, narrow_cast::size_type>(0)}; EXPECT_TRUE(s.size() == 0); EXPECT_TRUE(s.data() == nullptr); } @@ -229,27 +196,6 @@ TEST(span_test, from_pointer_length_constructor) auto workaround_macro = [=]() { const span s{p, 2}; }; EXPECT_DEATH(workaround_macro(), deathstring); } - - { - auto s = make_span(&arr[0], 2); - EXPECT_TRUE(s.size() == 2); - EXPECT_TRUE(s.data() == &arr[0]); - EXPECT_TRUE(s[0] == 1); - EXPECT_TRUE(s[1] == 2); - } - - { - int* p = nullptr; - auto s = make_span(p, narrow_cast::index_type>(0)); - EXPECT_TRUE(s.size() == 0); - EXPECT_TRUE(s.data() == nullptr); - } - - { - int* p = nullptr; - auto workaround_macro = [=]() { make_span(p, 2); }; - EXPECT_DEATH(workaround_macro(), deathstring); - } } TEST(span_test, from_pointer_pointer_construction) @@ -316,27 +262,6 @@ TEST(span_test, from_pointer_pointer_construction) // auto workaround_macro = [&]() { span s{&arr[0], p}; }; // EXPECT_DEATH(workaround_macro(), deathstring); //} - - { - auto s = make_span(&arr[0], &arr[2]); - EXPECT_TRUE(s.size() == 2); - EXPECT_TRUE(s.data() == &arr[0]); - EXPECT_TRUE(s[0] == 1); - EXPECT_TRUE(s[1] == 2); - } - - { - auto s = make_span(&arr[0], &arr[0]); - EXPECT_TRUE(s.size() == 0); - EXPECT_TRUE(s.data() == &arr[0]); - } - - { - int* p = nullptr; - auto s = make_span(p, p); - EXPECT_TRUE(s.size() == 0); - EXPECT_TRUE(s.data() == nullptr); - } } TEST(span_test, from_array_constructor) @@ -426,24 +351,6 @@ TEST(span_test, from_array_constructor) EXPECT_TRUE(s.size() == 1); } - { - const auto s = make_span(arr); - EXPECT_TRUE(s.size() == 5); - EXPECT_TRUE(s.data() == std::addressof(arr[0])); - } - - { - const auto s = make_span(std::addressof(arr2d[0]), 1); - EXPECT_TRUE(s.size() == 1); - EXPECT_TRUE(s.data() == std::addressof(arr2d[0])); - } - - { - const auto s = make_span(std::addressof(arr3d[0]), 1); - EXPECT_TRUE(s.size() == 1); - EXPECT_TRUE(s.data() == std::addressof(arr3d[0])); - } - AddressOverloaded ao_arr[5] = {}; { @@ -463,12 +370,6 @@ TEST(span_test, from_array_constructor) EXPECT_TRUE(s.data() == &arr[0][0][0]); } - { - auto s = make_span(&arr[0][0][0], 10); - EXPECT_TRUE(s.size() == 10); - EXPECT_TRUE(s.data() == &arr[0][0][0]); - } - delete[] arr; } @@ -478,21 +379,21 @@ TEST(span_test, from_array_constructor) { span s{arr}; - EXPECT_TRUE(s.size() == narrow_cast(arr.size())); + EXPECT_TRUE(s.size() == arr.size()); EXPECT_TRUE(s.data() == arr.data()); span cs{arr}; - EXPECT_TRUE(cs.size() == narrow_cast(arr.size())); + EXPECT_TRUE(cs.size() == arr.size()); EXPECT_TRUE(cs.data() == arr.data()); } { span s{arr}; - EXPECT_TRUE(s.size() == narrow_cast(arr.size())); + EXPECT_TRUE(s.size() == arr.size()); EXPECT_TRUE(s.data() == arr.data()); span cs{arr}; - EXPECT_TRUE(cs.size() == narrow_cast(arr.size())); + EXPECT_TRUE(cs.size() == arr.size()); EXPECT_TRUE(cs.data() == arr.data()); } @@ -507,7 +408,7 @@ TEST(span_test, from_array_constructor) { span fs{ao_arr}; - EXPECT_TRUE(fs.size() == narrow_cast(ao_arr.size())); + EXPECT_TRUE(fs.size() == ao_arr.size()); EXPECT_TRUE(ao_arr.data() == fs.data()); } @@ -550,30 +451,6 @@ TEST(span_test, from_array_constructor) // try to take a temporary std::array take_a_span(get_an_array()); } - - { - auto s = make_span(arr); - EXPECT_TRUE(s.size() == narrow_cast(arr.size())); - EXPECT_TRUE(s.data() == arr.data()); - } - - // This test checks for the bug found in gcc 6.1, 6.2, 6.3, 6.4, 6.5 7.1, 7.2, 7.3 - issue #590 - { - span s1 = make_span(arr); - - static span s2; - s2 = s1; - - #if defined(__GNUC__) && __GNUC__ == 6 && (__GNUC_MINOR__ == 4 || __GNUC_MINOR__ == 5) && \ - __GNUC_PATCHLEVEL__ == 0 && defined(__OPTIMIZE__) - // Known to be broken in gcc 6.4 and 6.5 with optimizations - // Issue in gcc: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83116 - EXPECT_TRUE(s1.size() == 4); - EXPECT_TRUE(s2.size() == 0); - #else - EXPECT_TRUE(s1.size() == s2.size()); - #endif - } } TEST(span_test, from_const_std_array_constructor) @@ -582,13 +459,13 @@ TEST(span_test, from_array_constructor) { span s{arr}; - EXPECT_TRUE(s.size() == narrow_cast(arr.size())); + EXPECT_TRUE(s.size() == arr.size()); EXPECT_TRUE(s.data() == arr.data()); } { span s{arr}; - EXPECT_TRUE(s.size() == narrow_cast(arr.size())); + EXPECT_TRUE(s.size() == arr.size()); EXPECT_TRUE(s.data() == arr.data()); } @@ -596,7 +473,7 @@ TEST(span_test, from_array_constructor) { span s{ao_arr}; - EXPECT_TRUE(s.size() == narrow_cast(ao_arr.size())); + EXPECT_TRUE(s.size() == ao_arr.size()); EXPECT_TRUE(s.data() == ao_arr.data()); } @@ -624,12 +501,6 @@ TEST(span_test, from_array_constructor) // try to take a temporary std::array take_a_span(get_an_array()); } - - { - auto s = make_span(arr); - EXPECT_TRUE(s.size() == narrow_cast(arr.size())); - EXPECT_TRUE(s.data() == arr.data()); - } } TEST(span_test, from_std_array_const_constructor) @@ -638,13 +509,13 @@ TEST(span_test, from_array_constructor) { span s{arr}; - EXPECT_TRUE(s.size() == narrow_cast(arr.size())); + EXPECT_TRUE(s.size() == arr.size()); EXPECT_TRUE(s.data() == arr.data()); } { span s{arr}; - EXPECT_TRUE(s.size() == narrow_cast(arr.size())); + EXPECT_TRUE(s.size() == arr.size()); EXPECT_TRUE(s.data() == arr.data()); } @@ -669,12 +540,6 @@ TEST(span_test, from_array_constructor) span s{arr}; } #endif - - { - auto s = make_span(arr); - EXPECT_TRUE(s.size() == narrow_cast(arr.size())); - EXPECT_TRUE(s.data() == arr.data()); - } } TEST(span_test, from_container_constructor) @@ -684,11 +549,11 @@ TEST(span_test, from_array_constructor) { span s{v}; - EXPECT_TRUE(s.size() == narrow_cast(v.size())); + EXPECT_TRUE(s.size() == v.size()); EXPECT_TRUE(s.data() == v.data()); span cs{v}; - EXPECT_TRUE(cs.size() == narrow_cast(v.size())); + EXPECT_TRUE(cs.size() == v.size()); EXPECT_TRUE(cs.data() == v.data()); } @@ -698,11 +563,11 @@ TEST(span_test, from_array_constructor) { #ifdef CONFIRM_COMPILATION_ERRORS span s{str}; - EXPECT_TRUE(s.size() == narrow_cast(str.size())); + EXPECT_TRUE(s.size() == str.size()); EXPECT_TRUE(s.data() == str.data())); #endif span cs{str}; - EXPECT_TRUE(cs.size() == narrow_cast(str.size())); + EXPECT_TRUE(cs.size() == str.size()); EXPECT_TRUE(cs.data() == str.data()); } @@ -711,7 +576,7 @@ TEST(span_test, from_array_constructor) span s{cstr}; #endif span cs{cstr}; - EXPECT_TRUE(cs.size() == narrow_cast(cstr.size())); + EXPECT_TRUE(cs.size() == cstr.size()); EXPECT_TRUE(cs.data() == cstr.data()); } @@ -763,16 +628,6 @@ TEST(span_test, from_array_constructor) span s{m}; #endif } - - { - auto s = make_span(v); - EXPECT_TRUE(s.size() == narrow_cast(v.size())); - EXPECT_TRUE(s.data() == v.data()); - - auto cs = make_span(cv); - EXPECT_TRUE(cs.size() == narrow_cast(cv.size())); - EXPECT_TRUE(cs.data() == cv.data()); - } } TEST(span_test, from_convertible_span_constructor){{span avd; @@ -987,7 +842,7 @@ TEST(span_test, from_array_constructor) EXPECT_TRUE(av.subspan(5).size() == 0); EXPECT_DEATH(av.subspan(6).size(), deathstring); const auto av2 = av.subspan(1); - for (int i = 0; i < 4; ++i) EXPECT_TRUE(av2[i] == i + 2); + for (std::size_t i = 0; i < 4; ++i) EXPECT_TRUE(av2[i] == static_cast(i) + 2); } { @@ -998,53 +853,7 @@ TEST(span_test, from_array_constructor) EXPECT_TRUE(av.subspan(5).size() == 0); EXPECT_DEATH(av.subspan(6).size(), deathstring); const auto av2 = av.subspan(1); - for (int i = 0; i < 4; ++i) EXPECT_TRUE(av2[i] == i + 2); - } - } - - TEST(span_test, at_call) - { - std::set_terminate([] { - std::cerr << "Expected Death. at_call"; - std::abort(); - }); - int arr[4] = {1, 2, 3, 4}; - - { - span s = arr; - EXPECT_TRUE(s.at(0) == 1); - EXPECT_DEATH(s.at(5), deathstring); - } - - { - int arr2d[2] = {1, 6}; - span s = arr2d; - EXPECT_TRUE(s.at(0) == 1); - EXPECT_TRUE(s.at(1) == 6); - EXPECT_DEATH(s.at(2), deathstring); - } - } - - TEST(span_test, operator_function_call) - { - std::set_terminate([] { - std::cerr << "Expected Death. operator_function_call"; - std::abort(); - }); - int arr[4] = {1, 2, 3, 4}; - - { - span s = arr; - EXPECT_TRUE(s(0) == 1); - EXPECT_DEATH(s(5), deathstring); - } - - { - int arr2d[2] = {1, 6}; - span s = arr2d; - EXPECT_TRUE(s(0) == 1); - EXPECT_TRUE(s(1) == 6); - EXPECT_DEATH(s(2), deathstring); + for (std::size_t i = 0; i < 4; ++i) EXPECT_TRUE(av2[i] == static_cast(i) + 2); } } @@ -1083,46 +892,6 @@ TEST(span_test, from_array_constructor) span::const_iterator cit3 = it + 4; EXPECT_TRUE(cit3 == s.cend()); } - - TEST(span_test, iterator_free_functions) - { - int a[] = {1, 2, 3, 4}; - span s{a}; - - EXPECT_TRUE((std::is_same::value)); - EXPECT_TRUE((std::is_same::value)); - - EXPECT_TRUE((std::is_same::value)); - EXPECT_TRUE((std::is_same::value)); - - EXPECT_TRUE((std::is_same::value)); - EXPECT_TRUE((std::is_same::value)); - - EXPECT_TRUE((std::is_same::value)); - EXPECT_TRUE((std::is_same::value)); - - EXPECT_TRUE(s.begin() == begin(s)); - EXPECT_TRUE(s.end() == end(s)); - - EXPECT_TRUE(s.cbegin() == cbegin(s)); - EXPECT_TRUE(s.cend() == cend(s)); - - EXPECT_TRUE(s.rbegin() == rbegin(s)); - EXPECT_TRUE(s.rend() == rend(s)); - - EXPECT_TRUE(s.crbegin() == crbegin(s)); - EXPECT_TRUE(s.crend() == crend(s)); - } - - TEST(span_test, ssize_free_function) - { - int a[] = {1, 2, 3, 4}; - span s{a}; - - EXPECT_TRUE((std::is_same::value)); - EXPECT_TRUE(s.size() == ssize(s)); - } - TEST(span_test, iterator_comparisons) { int a[] = {1, 2, 3, 4}; @@ -1170,6 +939,28 @@ TEST(span_test, from_array_constructor) } } + TEST(span_test, incomparable_iterators) + { + std::set_terminate([] { + std::cerr << "Expected Death. incomparable_iterators"; + std::abort(); + }); + + int a[] = {1, 2, 3, 4}; + int b[] = {1, 2, 3, 4}; + { + span s = a; + span s2 = b; +#if (__cplusplus > 201402L) + EXPECT_DEATH([[maybe_unused]] bool _ = (s.begin() == s2.begin()), deathstring); + EXPECT_DEATH([[maybe_unused]] bool _ = (s.begin() <= s2.begin()), deathstring); +#else + EXPECT_DEATH(bool _ = (s.begin() == s2.begin()), deathstring); + EXPECT_DEATH(bool _ = (s.begin() <= s2.begin()), deathstring); +#endif + } + } + TEST(span_test, begin_end) { std::set_terminate([] { @@ -1302,7 +1093,11 @@ TEST(span_test, from_array_constructor) auto beyond = s.rend(); EXPECT_TRUE(it != beyond); - EXPECT_DEATH(auto _ = *beyond , deathstring); +#if (__cplusplus > 201402L) + EXPECT_DEATH([[maybe_unused]] auto _ = *beyond , deathstring); +#else + EXPECT_DEATH(auto _ = *beyond , deathstring); +#endif EXPECT_TRUE(beyond - first == 4); EXPECT_TRUE(first - first == 0); @@ -1347,7 +1142,11 @@ TEST(span_test, from_array_constructor) auto beyond = s.crend(); EXPECT_TRUE(it != beyond); - EXPECT_DEATH(auto _ = *beyond, deathstring); +#if (__cplusplus > 201402L) + EXPECT_DEATH([[maybe_unused]] auto _ = *beyond, deathstring); +#else + EXPECT_DEATH(auto _ = *beyond, deathstring); +#endif EXPECT_TRUE(beyond - first == 4); EXPECT_TRUE(first - first == 0); @@ -1375,130 +1174,14 @@ TEST(span_test, from_array_constructor) } } - TEST(span_test, comparison_operators) - { - { - span s1; - span s2; - EXPECT_TRUE(s1 == s2); - EXPECT_FALSE(s1 != s2); - EXPECT_FALSE(s1 < s2); - EXPECT_TRUE(s1 <= s2); - EXPECT_FALSE(s1 > s2); - EXPECT_TRUE(s1 >= s2); - EXPECT_TRUE(s2 == s1); - EXPECT_FALSE(s2 != s1); - EXPECT_FALSE(s2 != s1); - EXPECT_TRUE(s2 <= s1); - EXPECT_FALSE(s2 > s1); - EXPECT_TRUE(s2 >= s1); - } - - { - int arr[] = {2, 1}; - span s1 = arr; - span s2 = arr; - - EXPECT_TRUE(s1 == s2); - EXPECT_FALSE(s1 != s2); - EXPECT_FALSE(s1 < s2); - EXPECT_TRUE(s1 <= s2); - EXPECT_FALSE(s1 > s2); - EXPECT_TRUE(s1 >= s2); - EXPECT_TRUE(s2 == s1); - EXPECT_FALSE(s2 != s1); - EXPECT_FALSE(s2 < s1); - EXPECT_TRUE(s2 <= s1); - EXPECT_FALSE(s2 > s1); - EXPECT_TRUE(s2 >= s1); - } - - { - int arr[] = {2, 1}; // bigger - - span s1; - span s2 = arr; - - EXPECT_TRUE(s1 != s2); - EXPECT_TRUE(s2 != s1); - EXPECT_FALSE(s1 == s2); - EXPECT_FALSE(s2 == s1); - EXPECT_TRUE(s1 < s2); - EXPECT_FALSE(s2 < s1); - EXPECT_TRUE(s1 <= s2); - EXPECT_FALSE(s2 <= s1); - EXPECT_TRUE(s2 > s1); - EXPECT_FALSE(s1 > s2); - EXPECT_TRUE(s2 >= s1); - EXPECT_FALSE(s1 >= s2); - } - - { - int arr1[] = {1, 2}; - int arr2[] = {1, 2}; - span s1 = arr1; - span s2 = arr2; - - EXPECT_TRUE(s1 == s2); - EXPECT_FALSE(s1 != s2); - EXPECT_FALSE(s1 < s2); - EXPECT_TRUE(s1 <= s2); - EXPECT_FALSE(s1 > s2); - EXPECT_TRUE(s1 >= s2); - EXPECT_TRUE(s2 == s1); - EXPECT_FALSE(s2 != s1); - EXPECT_FALSE(s2 < s1); - EXPECT_TRUE(s2 <= s1); - EXPECT_FALSE(s2 > s1); - EXPECT_TRUE(s2 >= s1); - } - - { - int arr[] = {1, 2, 3}; - - span s1 = {&arr[0], 2}; // shorter - span s2 = arr; // longer - - EXPECT_TRUE(s1 != s2); - EXPECT_TRUE(s2 != s1); - EXPECT_FALSE(s1 == s2); - EXPECT_FALSE(s2 == s1); - EXPECT_TRUE(s1 < s2); - EXPECT_FALSE(s2 < s1); - EXPECT_TRUE(s1 <= s2); - EXPECT_FALSE(s2 <= s1); - EXPECT_TRUE(s2 > s1); - EXPECT_FALSE(s1 > s2); - EXPECT_TRUE(s2 >= s1); - EXPECT_FALSE(s1 >= s2); - } - - { - int arr1[] = {1, 2}; // smaller - int arr2[] = {2, 1}; // bigger - - span s1 = arr1; - span s2 = arr2; - - EXPECT_TRUE(s1 != s2); - EXPECT_TRUE(s2 != s1); - EXPECT_FALSE(s1 == s2); - EXPECT_FALSE(s2 == s1); - EXPECT_TRUE(s1 < s2); - EXPECT_FALSE(s2 < s1); - EXPECT_TRUE(s1 <= s2); - EXPECT_FALSE(s2 <= s1); - EXPECT_TRUE(s2 > s1); - EXPECT_FALSE(s1 > s2); - EXPECT_TRUE(s2 >= s1); - EXPECT_FALSE(s1 >= s2); - } - } - TEST(span_test, as_bytes) { - int a[] = {1, 2, 3, 4}; + std::set_terminate([] { + std::cerr << "Expected Death. as_bytes"; + std::abort(); + }); + int a[] = {1, 2, 3, 4}; { const span s = a; EXPECT_TRUE(s.size() == 4); @@ -1523,9 +1206,15 @@ TEST(span_test, from_array_constructor) EXPECT_TRUE(static_cast(bs.data()) == static_cast(s.data())); EXPECT_TRUE(bs.size() == s.size_bytes()); } + + int b[5] = {1, 2, 3, 4, 5}; + { + span sp(begin(b), static_cast(-2)); + EXPECT_DEATH((void) sp.size_bytes(), deathstring); + } } - TEST(span_test, as_writeable_bytes) + TEST(span_test, as_writable_bytes) { int a[] = {1, 2, 3, 4}; @@ -1534,7 +1223,7 @@ TEST(span_test, from_array_constructor) // you should not be able to get writeable bytes for const objects span s = a; EXPECT_TRUE(s.size() == 4); - span bs = as_writeable_bytes(s); + span bs = as_writable_bytes(s); EXPECT_TRUE(static_cast(bs.data()) == static_cast(s.data())); EXPECT_TRUE(bs.size() == s.size_bytes()); #endif @@ -1542,7 +1231,7 @@ TEST(span_test, from_array_constructor) { span s; - const auto bs = as_writeable_bytes(s); + const auto bs = as_writable_bytes(s); EXPECT_TRUE(bs.size() == s.size()); EXPECT_TRUE(bs.size() == 0); EXPECT_TRUE(bs.size_bytes() == 0); @@ -1552,7 +1241,7 @@ TEST(span_test, from_array_constructor) { span s = a; - const auto bs = as_writeable_bytes(s); + const auto bs = as_writable_bytes(s); EXPECT_TRUE(static_cast(bs.data()) == static_cast(s.data())); EXPECT_TRUE(bs.size() == s.size_bytes()); } @@ -1590,12 +1279,16 @@ TEST(span_test, from_array_constructor) // even when done dynamically { + /* + // this now results in a compile-time error, rather than runtime. + // There is no suitable conversion from dynamic span to fixed span. span s = arr; auto f = [&]() { const span s2 = s; static_cast(s2); }; EXPECT_DEATH(f(), deathstring); + */ } // but doing so explicitly is ok @@ -1610,12 +1303,19 @@ TEST(span_test, from_array_constructor) static_cast(s1); } - // ...or dynamically + /* + // this is not a legal operation in std::span, so we are no longer supporting it + // conversion from span to span via call to `first` + // then convert from span to span + // The dynamic to fixed extents are not supported in the standard + // to make this work, span would need to be span. { + // NB: implicit conversion to span from span span s1 = s4.first(1); static_cast(s1); } + */ // initialization or assignment to static span that requires size INCREASE is not ok. int arr2[2] = {1, 2}; @@ -1637,12 +1337,15 @@ TEST(span_test, from_array_constructor) EXPECT_DEATH(f(), deathstring); } + /* + // This no longer compiles. There is no suitable conversion from dynamic span to a fixed size span. // this should fail - we are trying to assign a small dynamic span to a fixed_size larger one span av = arr2; auto f = [&]() { const span _s4 = av; static_cast(_s4); }; EXPECT_DEATH(f(), deathstring); + */ } TEST(span_test, interop_with_std_regex) @@ -1668,14 +1371,6 @@ TEST(span_test, from_array_constructor) EXPECT_TRUE(match[0].second == (f_it + 1)); } - TEST(span_test, interop_with_gsl_at) - { - int arr[5] = {1, 2, 3, 4, 5}; - span s{arr}; - EXPECT_TRUE(at(s, 0) == 1); - EXPECT_TRUE(at(s, 1) == 2); - } - TEST(span_test, default_constructible) { EXPECT_TRUE((std::is_default_constructible>::value)); @@ -1698,7 +1393,3 @@ TEST(span_test, from_array_constructor) EXPECT_DEATH(s2.front(), deathstring); EXPECT_DEATH(s2.back(), deathstring); } - -#if __clang__ || __GNUC__ -#pragma GCC diagnostic pop -#endif // __clang__ || __GNUC__ diff --git a/tests/strict_notnull_tests.cpp b/tests/strict_notnull_tests.cpp index 3c971db..3cf6911 100644 --- a/tests/strict_notnull_tests.cpp +++ b/tests/strict_notnull_tests.cpp @@ -14,28 +14,6 @@ // /////////////////////////////////////////////////////////////////////////////// -#ifdef _MSC_VER -// blanket turn off warnings from CppCoreCheck from catch -// so people aren't annoyed by them when running the tool. -#pragma warning(disable : 26440 26426) // from catch - -// Fix VS2015 build breaks in Release -#pragma warning(disable : 4702) // unreachable code -#endif - -#if __clang__ || __GNUC__ -//disable warnings from gtest -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wundef" -#endif // __clang__ || __GNUC__ - -#if __clang__ -#pragma GCC diagnostic ignored "-Wglobal-constructors" -#pragma GCC diagnostic ignored "-Wused-but-marked-unused" -#pragma GCC diagnostic ignored "-Wcovered-switch-default" -#pragma GCC diagnostic ignored "-Winconsistent-missing-destructor-override" -#endif // __clang__ - #include #include // for not_null, operator<, operator<=, operator> @@ -210,10 +188,3 @@ TEST(strict_notnull_tests, TestStrictNotNullConstructorTypeDeduction) #endif } #endif // #if defined(__cplusplus) && (__cplusplus >= 201703L) - -static_assert(std::is_nothrow_move_constructible>::value, - "strict_not_null must be no-throw move constructible"); - -#if __clang__ || __GNUC__ -#pragma GCC diagnostic pop -#endif // __clang__ || __GNUC__ diff --git a/tests/strided_span_tests.cpp b/tests/strided_span_tests.cpp index f5f3704..5a18f1b 100644 --- a/tests/strided_span_tests.cpp +++ b/tests/strided_span_tests.cpp @@ -14,28 +14,6 @@ // /////////////////////////////////////////////////////////////////////////////// -#ifdef _MSC_VER -// blanket turn off warnings from CppCoreCheck from catch -// so people aren't annoyed by them when running the tool. -#pragma warning(disable : 26440 26426) // from catch deprecated -#pragma warning(disable : 4996) // strided_span is in the process of being deprecated. - // Suppressing warnings until it is completely removed -#endif - -#if __clang__ || __GNUC__ -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wdeprecated-declarations" -//disable warnings from gtest -#pragma GCC diagnostic ignored "-Wundef" -#endif // __clang__ || __GNUC__ - -#if __clang__ -#pragma GCC diagnostic ignored "-Wglobal-constructors" -#pragma GCC diagnostic ignored "-Wused-but-marked-unused" -#pragma GCC diagnostic ignored "-Wcovered-switch-default" -#pragma GCC diagnostic ignored "-Winconsistent-missing-destructor-override" -#endif // __clang__ - #include #include // for byte #include // for narrow_cast @@ -810,7 +788,3 @@ TEST(strided_span_tests, strided_span_conversion) i++; } } - -#if __clang__ || __GNUC__ -#pragma GCC diagnostic pop -#endif // __clang__ || __GNUC__ diff --git a/tests/string_span_tests.cpp b/tests/string_span_tests.cpp index 24bf140..7a9f7fb 100644 --- a/tests/string_span_tests.cpp +++ b/tests/string_span_tests.cpp @@ -14,26 +14,6 @@ // /////////////////////////////////////////////////////////////////////////////// -#ifdef _MSC_VER -// blanket turn off warnings from CppCoreCheck from catch -// so people aren't annoyed by them when running the tool. -#pragma warning(disable : 26440 26426) // from catch - -#endif - -#if __clang__ || __GNUC__ -//disable warnings from gtest -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wundef" -#endif // __clang__ || __GNUC__ - -#if __clang__ -#pragma GCC diagnostic ignored "-Wglobal-constructors" -#pragma GCC diagnostic ignored "-Wused-but-marked-unused" -#pragma GCC diagnostic ignored "-Wcovered-switch-default" -#pragma GCC diagnostic ignored "-Winconsistent-missing-destructor-override" -#endif // __clang__ - #include #include // for Expects, fail_fast (ptr only) @@ -104,7 +84,7 @@ czstring_span<> CreateTempName(string_span<> span) { Expects(span.size() > 1); - int last = 0; + std::size_t last = 0; if (span.size() > 4) { span[0] = 't'; span[1] = 'm'; @@ -121,7 +101,7 @@ cwzstring_span<> CreateTempNameW(wstring_span<> span) { Expects(span.size() > 1); - int last = 0; + std::size_t last = 0; if (span.size() > 4) { span[0] = L't'; span[1] = L'm'; @@ -138,7 +118,7 @@ cu16zstring_span<> CreateTempNameU16(u16string_span<> span) { Expects(span.size() > 1); - int last = 0; + std::size_t last = 0; if (span.size() > 4) { span[0] = u't'; span[1] = u'm'; @@ -155,7 +135,7 @@ cu32zstring_span<> CreateTempNameU32(u32string_span<> span) { Expects(span.size() > 1); - int last = 0; + std::size_t last = 0; if (span.size() > 4) { span[0] = U't'; span[1] = U'm'; @@ -183,14 +163,14 @@ TEST(string_span_tests, TestConstructFromStdString) { std::string s = "Hello there world"; cstring_span<> v = s; - EXPECT_TRUE(v.length() == static_cast::index_type>(s.length())); + EXPECT_TRUE(v.length() == static_cast::size_type>(s.length())); } TEST(string_span_tests, TestConstructFromStdVector) { std::vector vec(5, 'h'); string_span<> v{vec}; - EXPECT_TRUE(v.length() == static_cast::index_type>(vec.size())); + EXPECT_TRUE(v.length() == static_cast::size_type>(vec.size())); } TEST(string_span_tests, TestStackArrayConstruction) @@ -252,7 +232,7 @@ TEST(string_span_tests, TestToString) char stack_string[] = "Hello"; cstring_span<> v = ensure_z(stack_string); auto s2 = gsl::to_string(v); - EXPECT_TRUE(static_cast::index_type>(s2.length()) == v.length()); + EXPECT_TRUE(static_cast::size_type>(s2.length()) == v.length()); EXPECT_TRUE(s2.length() == static_cast(5)); } @@ -265,7 +245,7 @@ TEST(string_span_tests, TestToBasicString) char stack_string[] = "Hello"; cstring_span<> v = ensure_z(stack_string); auto s2 = gsl::to_basic_string, ::std::allocator>(v); - EXPECT_TRUE(static_cast::index_type>(s2.length()) == v.length()); + EXPECT_TRUE(static_cast::size_type>(s2.length()) == v.length()); EXPECT_TRUE(s2.length() == static_cast(5)); } @@ -1226,16 +1206,12 @@ TEST(string_span_tests, as_bytes) EXPECT_TRUE(bs.size() == s.size_bytes()); } -TEST(string_span_tests, as_writeable_bytes) +TEST(string_span_tests, as_writable_bytes) { wchar_t buf[]{L"qwerty"}; wzstring_span<> v(buf); const auto s = v.as_string_span(); - const auto bs = as_writeable_bytes(s); + const auto bs = as_writable_bytes(s); EXPECT_TRUE(static_cast(bs.data()) == static_cast(s.data())); EXPECT_TRUE(bs.size() == s.size_bytes()); } - -#if __clang__ || __GNUC__ -#pragma GCC diagnostic pop -#endif // __clang__ || __GNUC__ diff --git a/tests/utils_tests.cpp b/tests/utils_tests.cpp index db6e8c5..f7f7ce3 100644 --- a/tests/utils_tests.cpp +++ b/tests/utils_tests.cpp @@ -14,27 +14,6 @@ // /////////////////////////////////////////////////////////////////////////////// -#ifdef _MSC_VER -// blanket turn off warnings from CppCoreCheck from catch -// so people aren't annoyed by them when running the tool. -#pragma warning(disable : 26440 26426) // from catch - -#endif - -#if __clang__ || __GNUC__ -//disable warnings from gtest -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wundef" -#endif // __clang__ || __GNUC__ - -#if __clang__ -#pragma GCC diagnostic ignored "-Wglobal-constructors" -#pragma GCC diagnostic ignored "-Wused-but-marked-unused" -#pragma GCC diagnostic ignored "-Wcovered-switch-default" -#pragma GCC diagnostic ignored "-Winconsistent-missing-destructor-override" -#endif // __clang__ - - #include #include // for narrow, finally, narrow_cast, narrowing_e... @@ -44,6 +23,7 @@ #include // for numeric_limits #include // for uint32_t, int32_t #include // for is_same +#include // for std::ptrdiff_t using namespace gsl; @@ -154,7 +134,3 @@ TEST(utils_tests, narrow) #endif } - -#if __clang__ || __GNUC__ -#pragma GCC diagnostic pop -#endif // __clang__ || __GNUC__