From 8579165d0a0ec8cbf90a20d2b84ed33def97868b Mon Sep 17 00:00:00 2001 From: "Jordan Maples [MSFT]" <49793787+JordanMaples@users.noreply.github.com> Date: Mon, 3 Feb 2020 10:56:31 -0800 Subject: [PATCH 01/45] change span from signed to unsigned to align to std --- include/gsl/span | 206 +++++++++++++++++++++------------------- include/gsl/string_span | 151 +++++++++++++++-------------- tests/span_tests.cpp | 48 +++++----- 3 files changed, 212 insertions(+), 193 deletions(-) diff --git a/include/gsl/span b/include/gsl/span index b3e5349..1b06fb3 100644 --- a/include/gsl/span +++ b/include/gsl/span @@ -26,16 +26,18 @@ #include // for ptrdiff_t, size_t, nullptr_t #include // for reverse_iterator, distance, random_access_... #include +#include // for std::addressof #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. @@ -70,9 +72,9 @@ namespace gsl { // [views.constants], constants -constexpr const std::ptrdiff_t dynamic_extent = -1; +constexpr const std::size_t dynamic_extent = std::numeric_limits::max(); -template +template class span; // implementation details @@ -83,7 +85,7 @@ namespace details { }; - template + template struct is_span_oracle> : std::true_type { }; @@ -108,7 +110,7 @@ namespace details { }; - template + template struct is_allowed_extent_conversion : public std::integral_constant @@ -151,10 +153,10 @@ namespace details : span_iterator(other.span_, other.index_) {} - GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute + GSL_SUPPRESS(bounds .1) // NO-FORMAT: attribute constexpr reference operator*() const { - Expects(index_ != span_->size()); + Expects(static_cast(index_) != span_->size()); return *(span_->data() + index_); } @@ -166,7 +168,7 @@ namespace details constexpr span_iterator& operator++() noexcept { - Expects(0 <= index_ && index_ != span_->size()); + Expects(0 <= index_ && static_cast(index_) != span_->size()); ++index_; return *this; } @@ -180,7 +182,7 @@ namespace details constexpr span_iterator& operator--() noexcept { - Expects(index_ != 0 && index_ <= span_->size()); + Expects(index_ != 0 && static_cast(index_) <= span_->size()); --index_; return *this; } @@ -198,7 +200,8 @@ namespace details return ret += n; } - friend constexpr span_iterator operator+(difference_type n, span_iterator const& rhs) noexcept + friend constexpr span_iterator operator+(difference_type n, + span_iterator const& rhs) noexcept { return rhs + n; } @@ -272,7 +275,7 @@ namespace details Expects((index_ + n) >= 0 && (index_ + n) <= span_->size()); } - GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute + GSL_SUPPRESS(bounds .1) // NO-FORMAT: attribute constexpr pointer _Unwrapped() const noexcept { // after seeking *this to a high water mark, or using one of the // _Verify_xxx functions above, unwrap this span_iterator to a raw @@ -287,7 +290,7 @@ namespace details #else static constexpr bool _Unwrap_when_unverified = false; #endif - GSL_SUPPRESS(con.3) // NO-FORMAT: attribute // TODO: false positive + GSL_SUPPRESS(con .3) // NO-FORMAT: attribute // TODO: false positive constexpr void _Seek_to(const pointer p) noexcept { // adjust the position of *this to previously verified location p // after _Unwrapped @@ -300,11 +303,11 @@ namespace details std::ptrdiff_t index_ = 0; }; - template + template class extent_type { public: - using index_type = std::ptrdiff_t; + using index_type = std::size_t; static_assert(Ext >= 0, "A fixed-size span must be >= 0 in size."); @@ -327,13 +330,16 @@ namespace details class extent_type { public: - using index_type = std::ptrdiff_t; + using index_type = std::size_t; 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(index_type size) : size_(size) + { + Expects(size != dynamic_extent); + } constexpr index_type size() const noexcept { return size_; } @@ -341,7 +347,7 @@ namespace details index_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 index_type = std::size_t; using pointer = element_type*; using reference = element_type&; + using difference_type = std::ptrdiff_t; using iterator = details::span_iterator, false>; using const_iterator = details::span_iterator, true>; @@ -379,11 +386,11 @@ public: template " SFINAE, // since "std::enable_if_t" is ill-formed when Extent is greater than 0. - class = std::enable_if_t<(Dependent || Extent <= 0)>> + class = std::enable_if_t<(Dependent || Extent == 0 || Extent == dynamic_extent)>> constexpr span() noexcept : storage_(nullptr, details::extent_type<0>()) {} - constexpr span(pointer ptr, index_type count) noexcept: storage_(ptr, count) {} + constexpr span(pointer ptr, index_type count) noexcept : storage_(ptr, count) {} constexpr span(pointer firstElem, pointer lastElem) noexcept : storage_(firstElem, std::distance(firstElem, lastElem)) @@ -397,24 +404,20 @@ public: template 0)>> constexpr span(std::array, N>& arr) noexcept : storage_(KnownNotNull{arr.data()}, details::extent_type()) - { - } + {} constexpr span(std::array, 0>&) noexcept : storage_(static_cast(nullptr), details::extent_type<0>()) - { - } + {} template 0)>> constexpr span(const std::array, N>& arr) noexcept : storage_(KnownNotNull{arr.data()}, details::extent_type()) - { - } + {} constexpr span(const std::array, 0>&) noexcept : storage_(static_cast(nullptr), details::extent_type<0>()) - { - } + {} // NB: the SFINAE here uses .data() as a incomplete/imperfect proxy for the requirement // on Container to be a contiguous sequence container. @@ -433,13 +436,14 @@ public: std::is_convertible::value && std::is_convertible().data())>::value>> - constexpr span(const Container& cont) noexcept : span(cont.data(), narrow(cont.size())) + constexpr span(const Container& cont) noexcept + : span(cont.data(), narrow(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,27 +455,27 @@ 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 - GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute + template + GSL_SUPPRESS(bounds .1) // NO-FORMAT: attribute constexpr span last() const noexcept { - Expects(Count >= 0 && size() - Count >= 0); + Expects(size() >= Count); return {data() + (size() - Count), Count}; } - template - GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute + template + GSL_SUPPRESS(bounds .1) // NO-FORMAT: attribute constexpr auto subspan() const noexcept -> typename details::calculate_subspan_type::type { - Expects((Offset >= 0 && size() - Offset >= 0) && + Expects((size() >= Offset) && (Count == dynamic_extent || (Count >= 0 && Offset + Count <= size()))); return {data() + Offset, Count == dynamic_extent ? size() - Offset : Count}; @@ -479,17 +483,19 @@ public: constexpr span first(index_type count) const noexcept { - Expects(count >= 0 && count <= size()); + Expects(count <= size()); return {data(), count}; } constexpr span last(index_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 + index_type count = dynamic_extent) const + noexcept { return make_subspan(offset, count, subspan_selector{}); } @@ -503,7 +509,7 @@ public: constexpr bool empty() const noexcept { return size() == 0; } // [span.elem], span element access - GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute + GSL_SUPPRESS(bounds .1) // NO-FORMAT: attribute constexpr reference operator[](index_type idx) const noexcept { Expects(CheckRange(idx, storage_.size())); @@ -512,23 +518,25 @@ public: constexpr reference front() const noexcept { - Expects(size() > 0); + Expects(size() != dynamic_extent && size() > 0); return data()[0]; } constexpr reference back() const noexcept { - Expects(size() > 0); + Expects(size() != dynamic_extent && 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); } - - + [[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(); } @@ -556,7 +564,7 @@ public: constexpr pointer _Unchecked_begin() const noexcept { return data(); } constexpr pointer _Unchecked_end() const noexcept { - GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute + GSL_SUPPRESS(bounds .1) // NO-FORMAT: attribute return data() + size(); } #endif // _MSC_VER @@ -607,13 +615,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); } @@ -629,12 +637,12 @@ private: // in subspans and constructors from arrays constexpr span(KnownNotNull ptr, index_type count) : storage_(ptr, count) {} - template + template class subspan_selector { }; - template + template span make_subspan(index_type offset, index_type count, subspan_selector) const { @@ -642,56 +650,56 @@ private: return tmp.subspan(offset, count); } - GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute + GSL_SUPPRESS(bounds .1) // NO-FORMAT: attribute span make_subspan(index_type offset, index_type count, subspan_selector) const { - Expects(offset >= 0 && size() - offset >= 0); + Expects(offset >= 0 && size() >= offset && size() != dynamic_extent); 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(GSL_USE_STATIC_CONSTEXPR_WORKAROUND) -template +template constexpr const typename span::index_type span::extent; #endif // [span.comparison], span comparison operators -template +template constexpr bool operator==(span l, span r) { return std::equal(l.begin(), l.end(), r.begin(), r.end()); } -template +template constexpr bool operator!=(span l, span r) { return !(l == r); } -template +template constexpr bool operator<(span l, span r) { return std::lexicographical_compare(l.begin(), l.end(), r.begin(), r.end()); } -template +template constexpr bool operator<=(span l, span r) { return !(l > r); } -template +template constexpr bool operator>(span l, span r) { return r < l; } -template +template constexpr bool operator>=(span l, span r) { return !(l < r); @@ -705,36 +713,33 @@ 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 { }; 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 { - GSL_SUPPRESS(type.1) // NO-FORMAT: attribute + GSL_SUPPRESS(type .1) // NO-FORMAT: attribute return {reinterpret_cast(s.data()), s.size_bytes()}; } -template ::value>> span::value> as_writeable_bytes(span s) noexcept { - GSL_SUPPRESS(type.1) // NO-FORMAT: attribute + GSL_SUPPRESS(type .1) // NO-FORMAT: attribute return {reinterpret_cast(s.data()), s.size_bytes()}; } @@ -773,7 +778,7 @@ constexpr span make_span(const Container& } template -constexpr span make_span(Ptr& cont, std::ptrdiff_t count) +constexpr span make_span(Ptr& cont, std::size_t count) { return span(cont, count); } @@ -785,7 +790,7 @@ constexpr span make_span(Ptr& cont) } // Specialization of gsl::at for span -template +template constexpr ElementType& at(span s, index i) { // No bounds checking here because it is done in span::operator[] called below @@ -793,57 +798,66 @@ constexpr ElementType& at(span s, index i) } // [span.obs] Free observer functions -template -constexpr typename span::index_type ssize(const span &span) noexcept +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 +template +constexpr typename span::iterator +begin(const span& span) noexcept { return span.begin(); } -template -constexpr typename span::iterator end(const span &span) noexcept +template +constexpr typename span::iterator +end(const span& span) noexcept { return span.end(); } -template -constexpr typename span::const_iterator cbegin(const span &span) noexcept +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 +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 +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 +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 +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 +template +constexpr typename span::const_reverse_iterator +crend(const span& span) noexcept { return span.crend(); } diff --git a/include/gsl/string_span b/include/gsl/string_span index 37cbe15..a1d2bb2 100644 --- a/include/gsl/string_span +++ b/include/gsl/string_span @@ -23,7 +23,7 @@ #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 @@ -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 = std::numeric_limits::max()) { 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; + GSL_SUPPRESS(bounds .1) // NO-FORMAT: attribute // TODO: suppress does not work + 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 = std::numeric_limits::max()) { 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: @@ -218,7 +222,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,7 +251,7 @@ 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) @@ -312,7 +316,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 +324,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,33 +366,34 @@ 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 { - GSL_SUPPRESS(type.1) // NO-FORMAT: attribute + GSL_SUPPRESS(type .1) // NO-FORMAT: attribute return {reinterpret_cast(s.data()), s.size_bytes()}; } -template ::value>> basic_string_span::value> as_writeable_bytes(basic_string_span s) noexcept { - GSL_SUPPRESS(type.1) // NO-FORMAT: attribute + GSL_SUPPRESS(type .1) // NO-FORMAT: attribute return {reinterpret_cast(s.data()), s.size_bytes()}; } // zero-terminated string span, used to convert // zero-terminated spans to legacy strings -template -class basic_zstring_span { +template +class basic_zstring_span +{ public: using value_type = CharT; using const_value_type = std::add_const_t; @@ -435,32 +440,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 +475,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 +486,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 +495,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 +505,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 +515,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 +531,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 +545,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 +560,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 +569,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 +584,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 +597,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 +611,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 +620,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 +635,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 +648,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 +662,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 +671,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 +686,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 +699,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/span_tests.cpp b/tests/span_tests.cpp index c41e013..166d64f 100644 --- a/tests/span_tests.cpp +++ b/tests/span_tests.cpp @@ -158,14 +158,14 @@ TEST(span_test, from_pointer_length_constructor) int arr[4] = {1, 2, 3, 4}; { - for (int i = 0; i < 4; ++i) + for (std::size_t i = 0; i < 4; ++i) { { span s = {&arr[0], i}; EXPECT_TRUE(s.size() == i); EXPECT_TRUE(s.data() == &arr[0]); EXPECT_TRUE(s.empty() == (i == 0)); - for (int j = 0; j < i; ++j) + for (std::size_t j = 0; j < i; ++j) { EXPECT_TRUE(arr[j] == s[j]); EXPECT_TRUE(arr[j] == s.at(j)); @@ -173,12 +173,12 @@ TEST(span_test, from_pointer_length_constructor) } } { - span s = {&arr[i], 4 - narrow_cast(i)}; + span s = {&arr[i], 4 - i}; EXPECT_TRUE(s.size() == 4 - i); EXPECT_TRUE(s.data() == &arr[i]); EXPECT_TRUE(s.empty() == ((4 - i) == 0)); - for (int j = 0; j < 4 - i; ++j) + for (std::size_t j = 0; j < 4 - i; ++j) { EXPECT_TRUE(arr[j + i] == s[j]); EXPECT_TRUE(arr[j + i] == s.at(j)); @@ -457,21 +457,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()); } @@ -486,7 +486,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()); } @@ -532,7 +532,7 @@ TEST(span_test, from_array_constructor) { auto s = make_span(arr); - EXPECT_TRUE(s.size() == narrow_cast(arr.size())); + EXPECT_TRUE(s.size() == arr.size()); EXPECT_TRUE(s.data() == arr.data()); } @@ -561,13 +561,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()); } @@ -575,7 +575,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()); } @@ -606,7 +606,7 @@ TEST(span_test, from_array_constructor) { auto s = make_span(arr); - EXPECT_TRUE(s.size() == narrow_cast(arr.size())); + EXPECT_TRUE(s.size() == arr.size()); EXPECT_TRUE(s.data() == arr.data()); } } @@ -617,13 +617,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()); } @@ -651,7 +651,7 @@ TEST(span_test, from_array_constructor) { auto s = make_span(arr); - EXPECT_TRUE(s.size() == narrow_cast(arr.size())); + EXPECT_TRUE(s.size() == arr.size()); EXPECT_TRUE(s.data() == arr.data()); } } @@ -663,11 +663,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()); } @@ -677,11 +677,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()); } @@ -690,7 +690,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()); } @@ -745,11 +745,11 @@ TEST(span_test, from_array_constructor) { auto s = make_span(v); - EXPECT_TRUE(s.size() == narrow_cast(v.size())); + EXPECT_TRUE(s.size() == v.size()); EXPECT_TRUE(s.data() == v.data()); auto cs = make_span(cv); - EXPECT_TRUE(cs.size() == narrow_cast(cv.size())); + EXPECT_TRUE(cs.size() == cv.size()); EXPECT_TRUE(cs.data() == cv.data()); } } From c31593dd0df8badff394ca81b2344f353774728e Mon Sep 17 00:00:00 2001 From: "Jordan Maples [MSFT]" <49793787+JordanMaples@users.noreply.github.com> Date: Mon, 3 Feb 2020 11:01:24 -0800 Subject: [PATCH 02/45] updating from test loop from int to size_t --- tests/span_tests.cpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/tests/span_tests.cpp b/tests/span_tests.cpp index 166d64f..d94ed20 100644 --- a/tests/span_tests.cpp +++ b/tests/span_tests.cpp @@ -966,7 +966,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] == i + 2); } { @@ -977,7 +977,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] == i + 2); } } @@ -1067,28 +1067,28 @@ TEST(span_test, from_array_constructor) { 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)); } @@ -1097,7 +1097,7 @@ TEST(span_test, from_array_constructor) { int a[] = {1, 2, 3, 4}; span s{a}; - + EXPECT_TRUE((std::is_same::value)); EXPECT_TRUE(s.size() == ssize(s)); } From ad71477183635a9fcd9f7d65d1a9b84ef4360997 Mon Sep 17 00:00:00 2001 From: "Jordan Maples [MSFT]" <49793787+JordanMaples@users.noreply.github.com> Date: Mon, 3 Feb 2020 12:26:15 -0800 Subject: [PATCH 03/45] fix build breaks --- include/gsl/gsl_algorithm | 4 ++-- include/gsl/span | 2 +- tests/span_tests.cpp | 4 ++-- tests/string_span_tests.cpp | 8 ++++---- 4 files changed, 9 insertions(+), 9 deletions(-) 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/span b/include/gsl/span index 1b06fb3..6e7e791 100644 --- a/include/gsl/span +++ b/include/gsl/span @@ -592,7 +592,7 @@ private: } else { - return idx >= 0 && idx < size; + return idx < size; } } diff --git a/tests/span_tests.cpp b/tests/span_tests.cpp index d94ed20..ac05af1 100644 --- a/tests/span_tests.cpp +++ b/tests/span_tests.cpp @@ -966,7 +966,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 (std::size_t 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); } { @@ -977,7 +977,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 (std::size_t 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); } } diff --git a/tests/string_span_tests.cpp b/tests/string_span_tests.cpp index e501bba..dd5a0de 100644 --- a/tests/string_span_tests.cpp +++ b/tests/string_span_tests.cpp @@ -84,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'; @@ -101,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'; @@ -118,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'; @@ -135,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'; From eabd9358f010ebe0c36b9238807a5a8fcaa002f6 Mon Sep 17 00:00:00 2001 From: "Jordan Maples [MSFT]" <49793787+JordanMaples@users.noreply.github.com> Date: Mon, 3 Feb 2020 12:46:37 -0800 Subject: [PATCH 04/45] addressing some comments --- include/gsl/span | 7 +++---- tests/span_tests.cpp | 5 ----- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/include/gsl/span b/include/gsl/span index 6e7e791..52af1f7 100644 --- a/include/gsl/span +++ b/include/gsl/span @@ -25,7 +25,6 @@ #include // for array #include // for ptrdiff_t, size_t, nullptr_t #include // for reverse_iterator, distance, random_access_... -#include #include // for std::addressof #include #include // for enable_if_t, declval, is_convertible, inte... @@ -72,7 +71,7 @@ namespace gsl { // [views.constants], constants -constexpr const std::size_t dynamic_extent = std::numeric_limits::max(); +constexpr const std::size_t dynamic_extent = -1; template class span; @@ -476,7 +475,7 @@ public: typename details::calculate_subspan_type::type { Expects((size() >= Offset) && - (Count == dynamic_extent || (Count >= 0 && Offset + Count <= size()))); + (Count == dynamic_extent || (Offset + Count <= size()))); return {data() + Offset, Count == dynamic_extent ? size() - Offset : Count}; } @@ -654,7 +653,7 @@ private: span make_subspan(index_type offset, index_type count, subspan_selector) const { - Expects(offset >= 0 && size() >= offset && size() != dynamic_extent); + Expects(size() >= offset && size() != dynamic_extent); if (count == dynamic_extent) { return {KnownNotNull{data() + offset}, size() - offset}; } diff --git a/tests/span_tests.cpp b/tests/span_tests.cpp index ac05af1..8d9fadd 100644 --- a/tests/span_tests.cpp +++ b/tests/span_tests.cpp @@ -30,11 +30,6 @@ #include // for integral_constant<>::value, is_default_co... #include // for vector -namespace gsl -{ -struct fail_fast; -} // namespace gsl - using namespace std; using namespace gsl; From 5b8cf5422b0d5330acb033872fa64150eedf4c8d Mon Sep 17 00:00:00 2001 From: "Jordan Maples [MSFT]" <49793787+JordanMaples@users.noreply.github.com> Date: Mon, 3 Feb 2020 12:49:57 -0800 Subject: [PATCH 05/45] casting -1 for dynamic extent --- include/gsl/span | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/gsl/span b/include/gsl/span index 52af1f7..b060113 100644 --- a/include/gsl/span +++ b/include/gsl/span @@ -71,7 +71,7 @@ namespace gsl { // [views.constants], constants -constexpr const std::size_t dynamic_extent = -1; +constexpr const std::size_t dynamic_extent = static_cast(-1); template class span; From 17e372c155bb9e71981f42c42349cb7947eac817 Mon Sep 17 00:00:00 2001 From: "Jordan Maples [MSFT]" <49793787+JordanMaples@users.noreply.github.com> Date: Mon, 3 Feb 2020 13:45:56 -0800 Subject: [PATCH 06/45] Update include/gsl/span Co-Authored-By: Casey Carter --- include/gsl/span | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/gsl/span b/include/gsl/span index b060113..1483762 100644 --- a/include/gsl/span +++ b/include/gsl/span @@ -25,7 +25,7 @@ #include // for array #include // for ptrdiff_t, size_t, nullptr_t #include // for reverse_iterator, distance, random_access_... -#include // for std::addressof +#include // for std::addressof #include #include // for enable_if_t, declval, is_convertible, inte... #include From 9bb900e834ba915f2a2f3abbfc4b5ef3828236d6 Mon Sep 17 00:00:00 2001 From: "Jordan Maples [MSFT]" <49793787+JordanMaples@users.noreply.github.com> Date: Mon, 3 Feb 2020 13:46:18 -0800 Subject: [PATCH 07/45] Update include/gsl/span Co-Authored-By: Casey Carter --- include/gsl/span | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/gsl/span b/include/gsl/span index 1483762..e96d644 100644 --- a/include/gsl/span +++ b/include/gsl/span @@ -475,7 +475,7 @@ public: typename details::calculate_subspan_type::type { Expects((size() >= Offset) && - (Count == dynamic_extent || (Offset + Count <= size()))); + (Count == dynamic_extent || (Count <= size() - Offset))); return {data() + Offset, Count == dynamic_extent ? size() - Offset : Count}; } From a430823b43bc32f51022fe16fc23d6325dfe5fce Mon Sep 17 00:00:00 2001 From: "Jordan Maples [MSFT]" <49793787+JordanMaples@users.noreply.github.com> Date: Mon, 3 Feb 2020 13:47:34 -0800 Subject: [PATCH 08/45] Update include/gsl/string_span Co-Authored-By: Casey Carter --- include/gsl/string_span | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/gsl/string_span b/include/gsl/string_span index a1d2bb2..fc0dfeb 100644 --- a/include/gsl/string_span +++ b/include/gsl/string_span @@ -26,7 +26,7 @@ #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__) From d0fdbdbffae2fb3f0cf2296d90749fc08e29517a Mon Sep 17 00:00:00 2001 From: "Jordan Maples [MSFT]" <49793787+JordanMaples@users.noreply.github.com> Date: Mon, 3 Feb 2020 13:52:00 -0800 Subject: [PATCH 09/45] fixing suppress spacing --- include/gsl/span | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/include/gsl/span b/include/gsl/span index b060113..2fb5bbd 100644 --- a/include/gsl/span +++ b/include/gsl/span @@ -152,7 +152,7 @@ namespace details : span_iterator(other.span_, other.index_) {} - GSL_SUPPRESS(bounds .1) // NO-FORMAT: attribute + GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute constexpr reference operator*() const { Expects(static_cast(index_) != span_->size()); @@ -274,7 +274,7 @@ namespace details Expects((index_ + n) >= 0 && (index_ + n) <= span_->size()); } - GSL_SUPPRESS(bounds .1) // NO-FORMAT: attribute + GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute constexpr pointer _Unwrapped() const noexcept { // after seeking *this to a high water mark, or using one of the // _Verify_xxx functions above, unwrap this span_iterator to a raw @@ -289,7 +289,7 @@ namespace details #else static constexpr bool _Unwrap_when_unverified = false; #endif - GSL_SUPPRESS(con .3) // NO-FORMAT: attribute // TODO: false positive + GSL_SUPPRESS(con.3) // NO-FORMAT: attribute // TODO: false positive constexpr void _Seek_to(const pointer p) noexcept { // adjust the position of *this to previously verified location p // after _Unwrapped @@ -462,7 +462,7 @@ public: } template - GSL_SUPPRESS(bounds .1) // NO-FORMAT: attribute + GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute constexpr span last() const noexcept { Expects(size() >= Count); @@ -470,7 +470,7 @@ public: } template - GSL_SUPPRESS(bounds .1) // NO-FORMAT: attribute + GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute constexpr auto subspan() const noexcept -> typename details::calculate_subspan_type::type { @@ -508,7 +508,7 @@ public: constexpr bool empty() const noexcept { return size() == 0; } // [span.elem], span element access - GSL_SUPPRESS(bounds .1) // NO-FORMAT: attribute + GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute constexpr reference operator[](index_type idx) const noexcept { Expects(CheckRange(idx, storage_.size())); @@ -563,7 +563,7 @@ public: constexpr pointer _Unchecked_begin() const noexcept { return data(); } constexpr pointer _Unchecked_end() const noexcept { - GSL_SUPPRESS(bounds .1) // NO-FORMAT: attribute + GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute return data() + size(); } #endif // _MSC_VER @@ -649,7 +649,7 @@ private: return tmp.subspan(offset, count); } - GSL_SUPPRESS(bounds .1) // NO-FORMAT: attribute + GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute span make_subspan(index_type offset, index_type count, subspan_selector) const { @@ -729,7 +729,7 @@ template span::value> as_bytes(span s) noexcept { - GSL_SUPPRESS(type .1) // NO-FORMAT: attribute + GSL_SUPPRESS(type.1) // NO-FORMAT: attribute return {reinterpret_cast(s.data()), s.size_bytes()}; } @@ -738,7 +738,7 @@ template ::value> as_writeable_bytes(span s) noexcept { - GSL_SUPPRESS(type .1) // NO-FORMAT: attribute + GSL_SUPPRESS(type.1) // NO-FORMAT: attribute return {reinterpret_cast(s.data()), s.size_bytes()}; } From d9d6ea81966fba0905a1c311433cf4aea24ed357 Mon Sep 17 00:00:00 2001 From: "Jordan Maples [MSFT]" <49793787+JordanMaples@users.noreply.github.com> Date: Mon, 3 Feb 2020 13:53:38 -0800 Subject: [PATCH 10/45] remove comparison to dynamic_extent --- include/gsl/span | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/gsl/span b/include/gsl/span index 7c5b24d..377181c 100644 --- a/include/gsl/span +++ b/include/gsl/span @@ -517,13 +517,13 @@ public: constexpr reference front() const noexcept { - Expects(size() != dynamic_extent && size() > 0); + Expects(size() > 0); return data()[0]; } constexpr reference back() const noexcept { - Expects(size() != dynamic_extent && size() > 0); + Expects(size() > 0); return data()[size() - 1]; } From 1815791af8b6fb1aac55a2a6b371719456d4102a Mon Sep 17 00:00:00 2001 From: "Jordan Maples [MSFT]" <49793787+JordanMaples@users.noreply.github.com> Date: Mon, 3 Feb 2020 16:26:36 -0800 Subject: [PATCH 11/45] Change iterator from Span* & ptrdiff_t to pointer, pointer, pointer --- include/gsl/span | 193 ++++++++++++++++++++++++++--------------------- 1 file changed, 109 insertions(+), 84 deletions(-) diff --git a/include/gsl/span b/include/gsl/span index 377181c..5f66c6c 100644 --- a/include/gsl/span +++ b/include/gsl/span @@ -122,140 +122,165 @@ namespace details { }; - 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 = ptrdiff_t; + using pointer = std::add_pointer_t; + using reference = std::add_lvalue_reference_t; - using reference = std::conditional_t&; - using pointer = std::add_pointer_t; - - span_iterator() = default; - - constexpr span_iterator(const Span* span, difference_type idx) noexcept - : span_(span), index_(idx) - {} - - friend span_iterator; - template * = nullptr> - constexpr span_iterator(const span_iterator& other) noexcept - : span_iterator(other.span_, other.index_) - {} - - GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute - constexpr reference operator*() const +#ifdef _MSC_VER + using _Unchecked_type = typename pointer; +#endif + constexpr operator span_iterator() const noexcept { - Expects(static_cast(index_) != span_->size()); - return *(span_->data() + index_); + return {begin_, end_, current_}; } - constexpr pointer operator->() const - { - Expects(index_ != span_->size()); - return span_->data() + index_; - } + constexpr reference operator*() const noexcept { return *operator->(); } + constexpr pointer operator->() const noexcept + { + Expects(begin_ && current_ && end_); + Expects(current_ < end_); + return current_; + } constexpr span_iterator& operator++() noexcept { - Expects(0 <= index_ && static_cast(index_) != span_->size()); - ++index_; + Expects(begin_ && current_ && end_); + Expects(current_ < end_); + ++current_; return *this; } constexpr span_iterator operator++(int) noexcept { - auto ret = *this; - ++(*this); + auto ret{*this}; + ++*this; return ret; } constexpr span_iterator& operator--() noexcept { - Expects(index_ != 0 && static_cast(index_) <= span_->size()); - --index_; + Expects(begin_ && current_ && end_); + Expects(current_ > begin_); + --current_; return *this; } constexpr span_iterator operator--(int) noexcept { - auto ret = *this; - --(*this); + auto 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; + Expects(begin_ && current_ && end_); + if (n > 0) Expects(end_ - current_ >= n); + if (n < 0) Expects(end_ - current_ >= -n); + current_ += n; + return *this; + } + + constexpr span_iterator operator+(const difference_type n) const noexcept + { + auto ret{*this}; return ret += n; } - friend constexpr span_iterator operator+(difference_type n, + friend constexpr span_iterator operator+(const difference_type n, span_iterator const& 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; + Expects(begin_ && end_ && current_); + if (n > 0) Expects(end_ - current_ >= 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; + auto ret{*this}; return ret -= n; } - constexpr span_iterator& operator-=(difference_type n) noexcept { return *this += -n; } - - constexpr difference_type operator-(span_iterator rhs) const noexcept + friend constexpr span_iterator operator-(const difference_type n, + span_iterator const& rhs) noexcept { - Expects(span_ == rhs.span_); - return index_ - rhs.index_; + return rhs - n; } - constexpr reference operator[](difference_type n) const noexcept { 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 difference_type operator-(const span_iterator& rhs) const noexcept { - return lhs.span_ == rhs.span_ && lhs.index_ == rhs.index_; + Expects(begin_ == rhs.begin_); + return current_ - rhs.current_; } - constexpr friend bool operator!=(span_iterator lhs, span_iterator rhs) noexcept + constexpr reference operator[](const difference_type n) const noexcept { - return !(lhs == rhs); + 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.index_ < rhs.index_; + return begin_ == rhs.begin_ && 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 !(*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_); + 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 !(*this < rhs); + } + + template < + class type2, + std::enable_if_t, value_type>::value, int> = 0> + constexpr bool operator<=(const span_iterator& rhs) const noexcept + { + return *this < rhs || *this == rhs; + } + + template < + class type2, + std::enable_if_t, value_type>::value, int> = 0> + constexpr bool operator>=(const span_iterator& rhs) const noexcept + { + return *this > rhs || *this == rhs; } #ifdef _MSC_VER @@ -264,14 +289,14 @@ 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_); // 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()); + Expects((current_ + n) >= begin_ && (current_ + n) <= end_); } GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute @@ -279,7 +304,7 @@ namespace details { // 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 @@ -293,13 +318,13 @@ namespace details 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 @@ -368,8 +393,8 @@ public: using reference = 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; @@ -540,11 +565,11 @@ public: 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 { return {data(), data() + size(), data()}; } + constexpr iterator end() const noexcept { return {data(), data() + size(), data() + size()}; } - constexpr const_iterator cbegin() const noexcept { return {this, 0}; } - constexpr const_iterator cend() const noexcept { return {this, size()}; } + constexpr const_iterator cbegin() const noexcept { return {data(), data() + size(), data()}; } + constexpr const_iterator cend() const noexcept { return {data(), data() + size(), data() + size()}; } constexpr reverse_iterator rbegin() const noexcept { return reverse_iterator{end()}; } constexpr reverse_iterator rend() const noexcept { return reverse_iterator{begin()}; } @@ -653,7 +678,7 @@ private: span make_subspan(index_type offset, index_type count, subspan_selector) const { - Expects(size() >= offset && size() != dynamic_extent); + Expects(size() >= offset); if (count == dynamic_extent) { return {KnownNotNull{data() + offset}, size() - offset}; } From f4ee6ee73b99ca8586e25c56ed627320144dd55f Mon Sep 17 00:00:00 2001 From: "Jordan Maples [MSFT]" <49793787+JordanMaples@users.noreply.github.com> Date: Mon, 3 Feb 2020 17:51:25 -0800 Subject: [PATCH 12/45] Update include/gsl/span Co-Authored-By: Casey Carter --- include/gsl/span | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/gsl/span b/include/gsl/span index 5f66c6c..4966961 100644 --- a/include/gsl/span +++ b/include/gsl/span @@ -294,7 +294,7 @@ namespace details } constexpr void _Verify_offset(const difference_type n) const noexcept - { // test that the iterator *this + n is a valid range in an STL + { // test that *this + n is within the span of this iterator STL // algorithm call Expects((current_ + n) >= begin_ && (current_ + n) <= end_); } From 24646c6f7cef01c817ae3af666efe54c362d5b51 Mon Sep 17 00:00:00 2001 From: "Jordan Maples [MSFT]" <49793787+JordanMaples@users.noreply.github.com> Date: Mon, 3 Feb 2020 17:51:45 -0800 Subject: [PATCH 13/45] Update include/gsl/span Co-Authored-By: Casey Carter --- include/gsl/span | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/gsl/span b/include/gsl/span index 4966961..5900da5 100644 --- a/include/gsl/span +++ b/include/gsl/span @@ -128,7 +128,7 @@ namespace details public: using iterator_category = std::random_access_iterator_tag; using value_type = std::remove_cv_t; - using difference_type = ptrdiff_t; + using difference_type = std::ptrdiff_t; using pointer = std::add_pointer_t; using reference = std::add_lvalue_reference_t; From 827fafd32c9da89bd521bac9c91a0d6e37be2f1d Mon Sep 17 00:00:00 2001 From: "Jordan Maples [MSFT]" <49793787+JordanMaples@users.noreply.github.com> Date: Mon, 3 Feb 2020 18:12:32 -0800 Subject: [PATCH 14/45] Update include/gsl/span Co-Authored-By: Casey Carter --- include/gsl/span | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/gsl/span b/include/gsl/span index 5900da5..c480f18 100644 --- a/include/gsl/span +++ b/include/gsl/span @@ -182,7 +182,7 @@ namespace details { Expects(begin_ && current_ && end_); if (n > 0) Expects(end_ - current_ >= n); - if (n < 0) Expects(end_ - current_ >= -n); + if (n < 0) Expects(current_ - begin_ >= -n); current_ += n; return *this; } From 81c2a1da15285d5cba3297caf3ad29bd09d0925c Mon Sep 17 00:00:00 2001 From: "Jordan Maples [MSFT]" <49793787+JordanMaples@users.noreply.github.com> Date: Mon, 3 Feb 2020 18:12:57 -0800 Subject: [PATCH 15/45] addressing feedback --- include/gsl/span | 32 +++----------------------------- 1 file changed, 3 insertions(+), 29 deletions(-) diff --git a/include/gsl/span b/include/gsl/span index 5f66c6c..ef7580c 100644 --- a/include/gsl/span +++ b/include/gsl/span @@ -333,7 +333,7 @@ namespace details public: using index_type = std::size_t; - static_assert(Ext >= 0, "A fixed-size span must be >= 0 in size."); + static_assert(Ext != dynamic_extent, "A fixed-size span must be >= 0 in size."); constexpr extent_type() noexcept {} @@ -417,7 +417,7 @@ public: constexpr span(pointer ptr, index_type count) noexcept : storage_(ptr, count) {} constexpr span(pointer firstElem, pointer lastElem) noexcept - : storage_(firstElem, std::distance(firstElem, lastElem)) + : storage_(firstElem, static_cast(std::distance(firstElem, lastElem))) {} template @@ -536,7 +536,7 @@ public: GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute constexpr reference operator[](index_type idx) const noexcept { - Expects(CheckRange(idx, storage_.size())); + Expects(idx < size()); return data()[idx]; } @@ -594,32 +594,6 @@ public: #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 < size; - } - } - // Needed to remove unnecessary null check in subspans struct KnownNotNull { From e0dc8095b3eb30ec4e75bac0b846f612d36d08ef Mon Sep 17 00:00:00 2001 From: "Jordan Maples [MSFT]" <49793787+JordanMaples@users.noreply.github.com> Date: Mon, 3 Feb 2020 18:13:14 -0800 Subject: [PATCH 16/45] addressing feedback --- include/gsl/span | 114 ++++++++++++++++++++++++----------------------- 1 file changed, 58 insertions(+), 56 deletions(-) diff --git a/include/gsl/span b/include/gsl/span index ef7580c..4f3b018 100644 --- a/include/gsl/span +++ b/include/gsl/span @@ -71,7 +71,7 @@ namespace gsl { // [views.constants], constants -constexpr const std::size_t dynamic_extent = static_cast(-1); +constexpr std::size_t dynamic_extent = static_cast(-1); template class span; @@ -122,25 +122,30 @@ namespace details { }; - template + template class span_iterator { public: using iterator_category = std::random_access_iterator_tag; - using value_type = std::remove_cv_t; - using difference_type = ptrdiff_t; - using pointer = std::add_pointer_t; - using reference = std::add_lvalue_reference_t; + using value_type = std::remove_cv_t; + using difference_type = std::ptrdiff_t; + using pointer = Type*; + using reference = Type&; #ifdef _MSC_VER - using _Unchecked_type = typename pointer; + using _Unchecked_type = pointer; #endif - constexpr operator span_iterator() const noexcept + constexpr operator span_iterator() const noexcept { return {begin_, end_, current_}; } - constexpr reference operator*() const noexcept { return *operator->(); } + constexpr reference operator*() const noexcept + { + Expects(begin_ && current_ && end_); + Expects(current_ < end_); + return *current_; + } constexpr pointer operator->() const noexcept { @@ -194,7 +199,7 @@ namespace details } friend constexpr span_iterator operator+(const difference_type n, - span_iterator const& rhs) noexcept + const span_iterator& rhs) noexcept { return rhs + n; } @@ -214,18 +219,12 @@ namespace details return ret -= n; } - friend constexpr span_iterator operator-(const difference_type n, - span_iterator const& rhs) noexcept - { - return rhs - n; - } - template < - class type2, - std::enable_if_t, value_type>::value, int> = 0> - constexpr difference_type operator-(const span_iterator& rhs) const noexcept + class Type2, + std::enable_if_t, value_type>::value, int> = 0> + constexpr difference_type operator-(const span_iterator& rhs) const noexcept { - Expects(begin_ == rhs.begin_); + Expects(begin_ == rhs.begin_ && end_ == rhs.end_); return current_ - rhs.current_; } @@ -235,52 +234,52 @@ namespace details } template < - class type2, - std::enable_if_t, value_type>::value, int> = 0> - constexpr bool operator==(const span_iterator& rhs) const noexcept + class Type2, + std::enable_if_t, value_type>::value, int> = 0> + constexpr bool operator==(const span_iterator& rhs) const noexcept { - return begin_ == rhs.begin_ && current_ == rhs.current_; + return begin_ == rhs.begin_ && end_ == rhs.end_ && current_ == rhs.current_; } template < - class type2, - std::enable_if_t, value_type>::value, int> = 0> - constexpr bool operator!=(const span_iterator& rhs) const noexcept + class Type2, + std::enable_if_t, value_type>::value, int> = 0> + constexpr bool operator!=(const span_iterator& rhs) const noexcept { return !(*this == rhs); } template < - class type2, - std::enable_if_t, value_type>::value, int> = 0> - constexpr bool operator<(const span_iterator& rhs) const noexcept + class Type2, + std::enable_if_t, value_type>::value, int> = 0> + constexpr bool operator<(const span_iterator& rhs) const noexcept { - Expects(begin_ == rhs.begin_); + Expects(begin_ == rhs.begin_ && end_ == rhs.end_); return current_ < rhs.current_; } template < - class type2, - std::enable_if_t, value_type>::value, int> = 0> - constexpr bool operator>(const span_iterator& rhs) const noexcept + class Type2, + std::enable_if_t, value_type>::value, int> = 0> + constexpr bool operator>(const span_iterator& rhs) const noexcept { return !(*this < rhs); } template < - class type2, - std::enable_if_t, value_type>::value, int> = 0> - constexpr bool operator<=(const span_iterator& rhs) const noexcept + class Type2, + std::enable_if_t, value_type>::value, int> = 0> + constexpr bool operator<=(const span_iterator& rhs) const noexcept { - return *this < rhs || *this == rhs; + return !(*this > rhs); } template < - class type2, - std::enable_if_t, value_type>::value, int> = 0> - constexpr bool operator>=(const span_iterator& rhs) const noexcept + class Type2, + std::enable_if_t, value_type>::value, int> = 0> + constexpr bool operator>=(const span_iterator& rhs) const noexcept { - return *this > rhs || *this == rhs; + return *!(this < rhs); } #ifdef _MSC_VER @@ -289,8 +288,9 @@ 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.begin_ == rhs.begin_ // range spans have to match - && lhs.end_ <= rhs.end_); // 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 @@ -299,7 +299,7 @@ namespace details Expects((current_ + n) >= begin_ && (current_ + n) <= end_); } - GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute + GSL_SUPPRESS(bounds .1) // NO-FORMAT: attribute constexpr pointer _Unwrapped() const noexcept { // after seeking *this to a high water mark, or using one of the // _Verify_xxx functions above, unwrap this span_iterator to a raw @@ -314,7 +314,7 @@ namespace details #else static constexpr bool _Unwrap_when_unverified = false; #endif - GSL_SUPPRESS(con.3) // NO-FORMAT: attribute // TODO: false positive + GSL_SUPPRESS(con .3) // NO-FORMAT: attribute // TODO: false positive constexpr void _Seek_to(const pointer p) noexcept { // adjust the position of *this to previously verified location p // after _Unwrapped @@ -487,7 +487,7 @@ public: } template - GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute + GSL_SUPPRESS(bounds .1) // NO-FORMAT: attribute constexpr span last() const noexcept { Expects(size() >= Count); @@ -495,12 +495,11 @@ public: } template - GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute + GSL_SUPPRESS(bounds .1) // NO-FORMAT: attribute constexpr auto subspan() const noexcept -> typename details::calculate_subspan_type::type { - Expects((size() >= Offset) && - (Count == dynamic_extent || (Count <= size() - Offset))); + Expects((size() >= Offset) && (Count == dynamic_extent || (Count <= size() - Offset))); return {data() + Offset, Count == dynamic_extent ? size() - Offset : Count}; } @@ -533,7 +532,7 @@ public: constexpr bool empty() const noexcept { return size() == 0; } // [span.elem], span element access - GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute + GSL_SUPPRESS(bounds .1) // NO-FORMAT: attribute constexpr reference operator[](index_type idx) const noexcept { Expects(idx < size()); @@ -569,7 +568,10 @@ public: constexpr iterator end() const noexcept { return {data(), data() + size(), data() + size()}; } constexpr const_iterator cbegin() const noexcept { return {data(), data() + size(), data()}; } - constexpr const_iterator cend() const noexcept { return {data(), data() + size(), data() + size()}; } + constexpr const_iterator cend() const noexcept + { + return {data(), data() + size(), data() + size()}; + } constexpr reverse_iterator rbegin() const noexcept { return reverse_iterator{end()}; } constexpr reverse_iterator rend() const noexcept { return reverse_iterator{begin()}; } @@ -588,7 +590,7 @@ public: constexpr pointer _Unchecked_begin() const noexcept { return data(); } constexpr pointer _Unchecked_end() const noexcept { - GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute + GSL_SUPPRESS(bounds .1) // NO-FORMAT: attribute return data() + size(); } #endif // _MSC_VER @@ -648,7 +650,7 @@ private: return tmp.subspan(offset, count); } - GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute + GSL_SUPPRESS(bounds .1) // NO-FORMAT: attribute span make_subspan(index_type offset, index_type count, subspan_selector) const { @@ -728,7 +730,7 @@ template span::value> as_bytes(span s) noexcept { - GSL_SUPPRESS(type.1) // NO-FORMAT: attribute + GSL_SUPPRESS(type .1) // NO-FORMAT: attribute return {reinterpret_cast(s.data()), s.size_bytes()}; } @@ -737,7 +739,7 @@ template ::value> as_writeable_bytes(span s) noexcept { - GSL_SUPPRESS(type.1) // NO-FORMAT: attribute + GSL_SUPPRESS(type .1) // NO-FORMAT: attribute return {reinterpret_cast(s.data()), s.size_bytes()}; } From 877816faa4090cbf2d4081397a71e7f24acc0b09 Mon Sep 17 00:00:00 2001 From: "Jordan Maples [MSFT]" <49793787+JordanMaples@users.noreply.github.com> Date: Mon, 3 Feb 2020 18:16:41 -0800 Subject: [PATCH 17/45] addressing feedback --- include/gsl/string_span | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/gsl/string_span b/include/gsl/string_span index fc0dfeb..269f9b3 100644 --- a/include/gsl/string_span +++ b/include/gsl/string_span @@ -109,7 +109,7 @@ namespace details // template span ensure_sentinel(T* seq, - std::size_t max = std::numeric_limits::max()) + std::size_t max = static_cast(-1)) { Ensures(seq != nullptr); @@ -131,7 +131,7 @@ span ensure_sentinel(T* seq, // template span ensure_z(CharT* const& sz, - std::size_t max = std::numeric_limits::max()) + std::size_t max = static_cast(-1)) { return ensure_sentinel(sz, max); } From 592c28c6d1c8259af0c8d67b22b5030537f163cf Mon Sep 17 00:00:00 2001 From: "Jordan Maples [MSFT]" <49793787+JordanMaples@users.noreply.github.com> Date: Mon, 3 Feb 2020 18:18:14 -0800 Subject: [PATCH 18/45] fixing spaces in gsl_suppress --- include/gsl/span | 18 +++++++++--------- include/gsl/string_span | 8 ++++---- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/include/gsl/span b/include/gsl/span index f5e850a..16add83 100644 --- a/include/gsl/span +++ b/include/gsl/span @@ -299,7 +299,7 @@ namespace details Expects((current_ + n) >= begin_ && (current_ + n) <= end_); } - GSL_SUPPRESS(bounds .1) // NO-FORMAT: attribute + GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute constexpr pointer _Unwrapped() const noexcept { // after seeking *this to a high water mark, or using one of the // _Verify_xxx functions above, unwrap this span_iterator to a raw @@ -314,7 +314,7 @@ namespace details #else static constexpr bool _Unwrap_when_unverified = false; #endif - GSL_SUPPRESS(con .3) // NO-FORMAT: attribute // TODO: false positive + GSL_SUPPRESS(con.3) // NO-FORMAT: attribute // TODO: false positive constexpr void _Seek_to(const pointer p) noexcept { // adjust the position of *this to previously verified location p // after _Unwrapped @@ -487,7 +487,7 @@ public: } template - GSL_SUPPRESS(bounds .1) // NO-FORMAT: attribute + GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute constexpr span last() const noexcept { Expects(size() >= Count); @@ -495,7 +495,7 @@ public: } template - GSL_SUPPRESS(bounds .1) // NO-FORMAT: attribute + GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute constexpr auto subspan() const noexcept -> typename details::calculate_subspan_type::type { @@ -532,7 +532,7 @@ public: constexpr bool empty() const noexcept { return size() == 0; } // [span.elem], span element access - GSL_SUPPRESS(bounds .1) // NO-FORMAT: attribute + GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute constexpr reference operator[](index_type idx) const noexcept { Expects(idx < size()); @@ -590,7 +590,7 @@ public: constexpr pointer _Unchecked_begin() const noexcept { return data(); } constexpr pointer _Unchecked_end() const noexcept { - GSL_SUPPRESS(bounds .1) // NO-FORMAT: attribute + GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute return data() + size(); } #endif // _MSC_VER @@ -650,7 +650,7 @@ private: return tmp.subspan(offset, count); } - GSL_SUPPRESS(bounds .1) // NO-FORMAT: attribute + GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute span make_subspan(index_type offset, index_type count, subspan_selector) const { @@ -730,7 +730,7 @@ template span::value> as_bytes(span s) noexcept { - GSL_SUPPRESS(type .1) // NO-FORMAT: attribute + GSL_SUPPRESS(type.1) // NO-FORMAT: attribute return {reinterpret_cast(s.data()), s.size_bytes()}; } @@ -739,7 +739,7 @@ template ::value> as_writeable_bytes(span s) noexcept { - GSL_SUPPRESS(type .1) // NO-FORMAT: attribute + GSL_SUPPRESS(type.1) // NO-FORMAT: attribute return {reinterpret_cast(s.data()), s.size_bytes()}; } diff --git a/include/gsl/string_span b/include/gsl/string_span index 269f9b3..c4752db 100644 --- a/include/gsl/string_span +++ b/include/gsl/string_span @@ -114,11 +114,11 @@ span ensure_sentinel(T* seq, Ensures(seq != nullptr); GSL_SUPPRESS( - f .23) // NO-FORMAT: attribute // TODO: false positive // TODO: suppress does not work + 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 + GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute // TODO: suppress does not work while (static_cast(cur - seq) < max && *cur != Sentinel) ++cur; Ensures(*cur == Sentinel); return {seq, static_cast(cur - seq)}; @@ -376,7 +376,7 @@ template basic_string_span::value> as_bytes(basic_string_span s) noexcept { - GSL_SUPPRESS(type .1) // NO-FORMAT: attribute + GSL_SUPPRESS(type.1) // NO-FORMAT: attribute return {reinterpret_cast(s.data()), s.size_bytes()}; } @@ -385,7 +385,7 @@ template ::value> as_writeable_bytes(basic_string_span s) noexcept { - GSL_SUPPRESS(type .1) // NO-FORMAT: attribute + GSL_SUPPRESS(type.1) // NO-FORMAT: attribute return {reinterpret_cast(s.data()), s.size_bytes()}; } From 49e7ed1ebfcf80fcfd60c53d35f7a782b6e030a3 Mon Sep 17 00:00:00 2001 From: "Jordan Maples [MSFT]" <49793787+JordanMaples@users.noreply.github.com> Date: Mon, 3 Feb 2020 18:27:09 -0800 Subject: [PATCH 19/45] updating comparisons --- include/gsl/span | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/gsl/span b/include/gsl/span index 16add83..170c746 100644 --- a/include/gsl/span +++ b/include/gsl/span @@ -271,7 +271,7 @@ namespace details std::enable_if_t, value_type>::value, int> = 0> constexpr bool operator<=(const span_iterator& rhs) const noexcept { - return !(*this > rhs); + return !(rhs < *this); } template < @@ -279,7 +279,7 @@ namespace details std::enable_if_t, value_type>::value, int> = 0> constexpr bool operator>=(const span_iterator& rhs) const noexcept { - return *!(this < rhs); + return !(*this < rhs); } #ifdef _MSC_VER From 4ec7058b560b0767222fdba9c0f114ebcd58db87 Mon Sep 17 00:00:00 2001 From: "Jordan Maples [MSFT]" <49793787+JordanMaples@users.noreply.github.com> Date: Mon, 3 Feb 2020 18:31:21 -0800 Subject: [PATCH 20/45] Update include/gsl/span Co-Authored-By: Casey Carter --- include/gsl/span | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/gsl/span b/include/gsl/span index 170c746..09a10a9 100644 --- a/include/gsl/span +++ b/include/gsl/span @@ -263,7 +263,7 @@ namespace details std::enable_if_t, value_type>::value, int> = 0> constexpr bool operator>(const span_iterator& rhs) const noexcept { - return !(*this < rhs); + return rhs < *this; } template < From e9fea77bcb0608718b14dfa21cb9428244e4d46b Mon Sep 17 00:00:00 2001 From: "Jordan Maples [MSFT]" <49793787+JordanMaples@users.noreply.github.com> Date: Mon, 3 Feb 2020 18:31:50 -0800 Subject: [PATCH 21/45] Update include/gsl/span Co-Authored-By: Casey Carter --- include/gsl/span | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/gsl/span b/include/gsl/span index 09a10a9..62ea0a0 100644 --- a/include/gsl/span +++ b/include/gsl/span @@ -207,7 +207,7 @@ namespace details constexpr span_iterator& operator-=(const difference_type n) noexcept { Expects(begin_ && end_ && current_); - if (n > 0) Expects(end_ - current_ >= n); + if (n > 0) Expects(current_ - begin_ >= n); if (n < 0) Expects(end_ - current_ >= -n); current_ -= n; return *this; From 0c6ce424abe6a75c90d8c3c038736cd12af75b18 Mon Sep 17 00:00:00 2001 From: "Jordan Maples [MSFT]" <49793787+JordanMaples@users.noreply.github.com> Date: Tue, 4 Feb 2020 12:01:27 -0800 Subject: [PATCH 22/45] refactoring index_type to size_type, changing expects --- include/gsl/span | 91 ++++++++++++++++++++++++++++-------------------- 1 file changed, 54 insertions(+), 37 deletions(-) diff --git a/include/gsl/span b/include/gsl/span index 09a10a9..83a2e02 100644 --- a/include/gsl/span +++ b/include/gsl/span @@ -296,7 +296,7 @@ namespace details constexpr void _Verify_offset(const difference_type n) const noexcept { // test that *this + n is within the span of this iterator STL // algorithm call - Expects((current_ + n) >= begin_ && (current_ + n) <= end_); + Expects( n <= (current_ - begin_) && n <= (end_ - current_)); } GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute @@ -331,13 +331,13 @@ namespace details class extent_type { public: - using index_type = std::size_t; + using size_type = std::size_t; static_assert(Ext != dynamic_extent, "A fixed-size span must be >= 0 in size."); constexpr extent_type() noexcept {} - template + template constexpr extent_type(extent_type ext) { static_assert(Other == Ext || Other == dynamic_extent, @@ -345,30 +345,30 @@ namespace details 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::size_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) + 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 @@ -388,7 +388,7 @@ public: // constants and types using element_type = ElementType; using value_type = std::remove_cv_t; - using index_type = std::size_t; + using size_type = std::size_t; using pointer = element_type*; using reference = element_type&; using difference_type = std::ptrdiff_t; @@ -398,12 +398,12 @@ public: using reverse_iterator = std::reverse_iterator; using const_reverse_iterator = std::reverse_iterator; - using size_type = index_type; + using index_type [[deprecated("use size_type instead of index_type")]] = size_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 @@ -414,7 +414,7 @@ public: 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) {} constexpr span(pointer firstElem, pointer lastElem) noexcept : storage_(firstElem, static_cast(std::distance(firstElem, lastElem))) @@ -451,7 +451,7 @@ public: std::is_convertible::value && std::is_convertible().data())>::value>> - constexpr span(Container& cont) noexcept : span(cont.data(), narrow(cont.size())) + constexpr span(Container& cont) noexcept : span(cont.data(), narrow(cont.size())) {} template ().data())>::value>> constexpr span(const Container& cont) noexcept - : span(cont.data(), narrow(cont.size())) + : span(cont.data(), narrow(cont.size())) {} constexpr span(const span& other) noexcept = default; @@ -504,36 +504,36 @@ public: 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 <= 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 + 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)); + return size() * narrow_cast(sizeof(element_type)); } constexpr bool empty() const noexcept { return size() == 0; } // [span.elem], span element access GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute - constexpr reference operator[](index_type idx) const noexcept + constexpr reference operator[](size_type idx) const noexcept { Expects(idx < size()); return data()[idx]; @@ -552,11 +552,11 @@ public: } // 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 + [[deprecated("Use operator[]")]] constexpr reference at(size_type idx) const noexcept { return this->operator[](idx); } - [[deprecated("Use operator[]")]] constexpr reference operator()(index_type idx) const noexcept + [[deprecated("Use operator[]")]] constexpr reference operator()(size_type idx) const noexcept { return this->operator[](idx); } @@ -564,13 +564,30 @@ public: constexpr pointer data() const noexcept { return storage_.data(); } // [span.iter], span iterator support - constexpr iterator begin() const noexcept { return {data(), data() + size(), data()}; } - constexpr iterator end() const noexcept { return {data(), data() + size(), data() + size()}; } + constexpr iterator begin() const noexcept + { + const auto data = storage_.data(); + return {data, data + size(), data}; + } + + constexpr iterator end() const noexcept + { + const auto data = storage_.data(); + const auto size = storage_.size(); + return {data, data + size, data + size}; + } + + constexpr const_iterator cbegin() const noexcept + { + const auto data = storage_.data(); + return {data, data + size(), data}; + } - constexpr const_iterator cbegin() const noexcept { return {data(), data() + size(), data()}; } constexpr const_iterator cend() const noexcept { - return {data(), data() + size(), data() + size()}; + const auto data = storage_.data(); + const auto size = storage_.size(); + return {data, data + size, data + size}; } constexpr reverse_iterator rbegin() const noexcept { return reverse_iterator{end()}; } @@ -635,7 +652,7 @@ 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) : storage_(ptr, count) {} template class subspan_selector @@ -643,7 +660,7 @@ private: }; template - span make_subspan(index_type offset, index_type count, + span make_subspan(size_type offset, size_type count, subspan_selector) const { const span tmp(*this); @@ -651,7 +668,7 @@ private: } GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute - span make_subspan(index_type offset, index_type count, + span make_subspan(size_type offset, size_type count, subspan_selector) const { Expects(size() >= offset); @@ -665,7 +682,7 @@ private: #if defined(GSL_USE_STATIC_CONSTEXPR_WORKAROUND) template -constexpr const typename span::index_type span::extent; +constexpr const typename span::size_type span::extent; #endif // [span.comparison], span comparison operators @@ -748,7 +765,7 @@ as_writeable_bytes(span s) noexcept // template constexpr span make_span(ElementType* ptr, - typename span::index_type count) + typename span::size_type count) { return span(ptr, count); } @@ -799,7 +816,7 @@ constexpr ElementType& at(span s, index i) // [span.obs] Free observer functions template -constexpr typename span::index_type +constexpr typename span::size_type ssize(const span& span) noexcept { return span.size(); From 61c6ef8d426dd4869789be9b8432c6cb4454a8bb Mon Sep 17 00:00:00 2001 From: "Jordan Maples [MSFT]" <49793787+JordanMaples@users.noreply.github.com> Date: Tue, 4 Feb 2020 13:30:03 -0800 Subject: [PATCH 23/45] remove index_type from string_span, update comments --- include/gsl/span | 11 +++++------ include/gsl/string_span | 30 ++++++++++++++---------------- 2 files changed, 19 insertions(+), 22 deletions(-) diff --git a/include/gsl/span b/include/gsl/span index c919f38..737ef80 100644 --- a/include/gsl/span +++ b/include/gsl/span @@ -185,7 +185,7 @@ namespace details constexpr span_iterator& operator+=(const difference_type n) noexcept { - Expects(begin_ && current_ && end_); + if (n != 0) Expects(begin_ && current_ && end_); if (n > 0) Expects(end_ - current_ >= n); if (n < 0) Expects(current_ - begin_ >= -n); current_ += n; @@ -206,7 +206,7 @@ namespace details constexpr span_iterator& operator-=(const difference_type n) noexcept { - Expects(begin_ && end_ && current_); + if (n != 0) Expects(begin_ && current_ && end_); if (n > 0) Expects(current_ - begin_ >= n); if (n < 0) Expects(end_ - current_ >= -n); current_ -= n; @@ -294,8 +294,7 @@ namespace details } constexpr void _Verify_offset(const difference_type n) const noexcept - { // test that *this + n is within the span of this iterator STL - // algorithm call + { // test that *this + n is within the range of this call Expects( n <= (current_ - begin_) && n <= (end_ - current_)); } @@ -408,8 +407,8 @@ public: // [span.cons], span constructors, copy, assignment, and destructor template " SFINAE, - // since "std::enable_if_t" is ill-formed when Extent is greater than 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 || Extent == 0 || Extent == dynamic_extent)>> constexpr span() noexcept : storage_(nullptr, details::extent_type<0>()) {} diff --git a/include/gsl/string_span b/include/gsl/string_span index c4752db..27b8977 100644 --- a/include/gsl/string_span +++ b/include/gsl/string_span @@ -184,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; @@ -201,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 @@ -258,49 +256,49 @@ public: : 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(); } From 5a1e4f39537330c579662a76a9a9b5c8580ad708 Mon Sep 17 00:00:00 2001 From: "Jordan Maples [MSFT]" <49793787+JordanMaples@users.noreply.github.com> Date: Tue, 4 Feb 2020 15:31:33 -0800 Subject: [PATCH 24/45] update index_type to size_type, fix a couple Expects --- include/gsl/span | 10 ++++++---- tests/span_tests.cpp | 14 +++++++------- tests/string_span_tests.cpp | 8 ++++---- 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/include/gsl/span b/include/gsl/span index 737ef80..5049b97 100644 --- a/include/gsl/span +++ b/include/gsl/span @@ -143,14 +143,14 @@ namespace details constexpr reference operator*() const noexcept { Expects(begin_ && current_ && end_); - Expects(current_ < end_); + Expects(begin_ <= current_ && current_ < end_); return *current_; } constexpr pointer operator->() const noexcept { Expects(begin_ && current_ && end_); - Expects(current_ < end_); + Expects(begin_ <= current_ && current_ < end_); return current_; } constexpr span_iterator& operator++() noexcept @@ -171,7 +171,7 @@ namespace details constexpr span_iterator& operator--() noexcept { Expects(begin_ && current_ && end_); - Expects(current_ > begin_); + Expects(begin_ < current_); --current_; return *this; } @@ -295,7 +295,9 @@ namespace details constexpr void _Verify_offset(const difference_type n) const noexcept { // test that *this + n is within the range of this call - Expects( n <= (current_ - begin_) && n <= (end_ - current_)); + if (n != 0) Expects(begin_ && current_ && end_); + if (n > 0) Expects(end_ - current_ >= n); + if (n < 0) Expects(current_ - begin_ >= -n); } GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute diff --git a/tests/span_tests.cpp b/tests/span_tests.cpp index 8d9fadd..99ee0d8 100644 --- a/tests/span_tests.cpp +++ b/tests/span_tests.cpp @@ -105,17 +105,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); } @@ -134,11 +134,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); } @@ -193,7 +193,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); } @@ -214,7 +214,7 @@ TEST(span_test, from_pointer_length_constructor) { int* p = nullptr; - auto s = make_span(p, narrow_cast::index_type>(0)); + auto s = make_span(p, narrow_cast::size_type>(0)); EXPECT_TRUE(s.size() == 0); EXPECT_TRUE(s.data() == nullptr); } diff --git a/tests/string_span_tests.cpp b/tests/string_span_tests.cpp index dd5a0de..c1f8cf4 100644 --- a/tests/string_span_tests.cpp +++ b/tests/string_span_tests.cpp @@ -163,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) @@ -232,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)); } @@ -245,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)); } From d7e16111377e5bf0ca9b766f4445fe4754542ed9 Mon Sep 17 00:00:00 2001 From: "Jordan Maples [MSFT]" <49793787+JordanMaples@users.noreply.github.com> Date: Tue, 4 Feb 2020 16:53:43 -0800 Subject: [PATCH 25/45] gsl::index ptrdiff_t -> size_t. remove span::at span::operator(). --- include/gsl/gsl_util | 13 +++++----- include/gsl/span | 48 ++++++++++++++-------------------- tests/at_tests.cpp | 26 +++++++------------ tests/span_tests.cpp | 60 +++---------------------------------------- tests/utils_tests.cpp | 3 ++- 5 files changed, 39 insertions(+), 111 deletions(-) diff --git a/include/gsl/gsl_util b/include/gsl/gsl_util index d1f7f33..53141e6 100644 --- a/include/gsl/gsl_util +++ b/include/gsl/gsl_util @@ -49,7 +49,7 @@ namespace gsl // // index type for all container indexes/subscripts/sizes -using index = std::ptrdiff_t; +using index = std::size_t; // final_action allows you to ensure something gets run at the end of a scope template @@ -129,8 +129,8 @@ GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute constexpr T& at(T (&arr)[N], const index i) { - Expects(i >= 0 && i < narrow_cast(N)); - return arr[narrow_cast(i)]; + Expects(i >= 0 && i < N); + return arr[i]; } template @@ -138,16 +138,15 @@ GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute constexpr auto at(Cont& cont, const index i) -> decltype(cont[cont.size()]) { - Expects(i >= 0 && i < narrow_cast(cont.size())); - using size_type = decltype(cont.size()); - return cont[narrow_cast(i)]; + Expects(i >= 0 && i < cont.size()); + return cont[i]; } template GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute constexpr T at(const std::initializer_list cont, const index i) { - Expects(i >= 0 && i < narrow_cast(cont.size())); + Expects(i >= 0 && i < cont.size()); return *(cont.begin() + i); } diff --git a/include/gsl/span b/include/gsl/span index 5049b97..548587b 100644 --- a/include/gsl/span +++ b/include/gsl/span @@ -552,16 +552,6 @@ public: 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(size_type idx) const noexcept - { - return this->operator[](idx); - } - [[deprecated("Use operator[]")]] constexpr reference operator()(size_type idx) const noexcept - { - return this->operator[](idx); - } - constexpr pointer data() const noexcept { return storage_.data(); } // [span.iter], span iterator support @@ -817,67 +807,67 @@ constexpr ElementType& at(span s, index i) // [span.obs] Free observer functions template -constexpr typename span::size_type -ssize(const span& span) noexcept +constexpr std::ptrdiff_t +ssize(const span& s) noexcept { - return span.size(); + return static_cast(s.size()); } // [span.iter] Free functions for begin/end functions template constexpr typename span::iterator -begin(const span& span) noexcept +begin(const span& s) noexcept { - return span.begin(); + return s.begin(); } template constexpr typename span::iterator -end(const span& span) noexcept +end(const span& s) noexcept { - return span.end(); + return s.end(); } template constexpr typename span::const_iterator -cbegin(const span& span) noexcept +cbegin(const span& s) noexcept { - return span.cbegin(); + return s.cbegin(); } template constexpr typename span::const_iterator -cend(const span& span) noexcept +cend(const span& s) noexcept { - return span.cend(); + return s.cend(); } template constexpr typename span::reverse_iterator -rbegin(const span& span) noexcept +rbegin(const span& s) noexcept { - return span.rbegin(); + return s.rbegin(); } template constexpr typename span::reverse_iterator -rend(const span& span) noexcept +rend(const span& s) noexcept { - return span.rend(); + return s.rend(); } template constexpr typename span::const_reverse_iterator -crbegin(const span& span) noexcept +crbegin(const span& s) noexcept { - return span.crbegin(); + return s.crbegin(); } template constexpr typename span::const_reverse_iterator -crend(const span& span) noexcept +crend(const span& s) noexcept { - return span.crend(); + return s.crend(); } } // namespace gsl diff --git a/tests/at_tests.cpp b/tests/at_tests.cpp index be2c7b8..0580301 100644 --- a/tests/at_tests.cpp +++ b/tests/at_tests.cpp @@ -33,7 +33,7 @@ TEST(at_tests, static_array) int a[4] = {1, 2, 3, 4}; const int(&c_a)[4] = a; - for (int i = 0; i < 4; ++i) { + for (std::size_t i = 0; i < 4; ++i) { EXPECT_TRUE(&gsl::at(a, i) == &a[i]); EXPECT_TRUE(&gsl::at(c_a, i) == &a[i]); } @@ -43,9 +43,7 @@ TEST(at_tests, static_array) std::abort(); }); - EXPECT_DEATH(gsl::at(a, -1), deathstring); EXPECT_DEATH(gsl::at(a, 4), deathstring); - EXPECT_DEATH(gsl::at(c_a, -1), deathstring); EXPECT_DEATH(gsl::at(c_a, 4), deathstring); } @@ -54,7 +52,7 @@ TEST(at_tests, std_array) std::array a = {1, 2, 3, 4}; const std::array& c_a = a; - for (int i = 0; i < 4; ++i) { + for (std::size_t i = 0; i < 4; ++i) { EXPECT_TRUE(&gsl::at(a, i) == &a[static_cast(i)]); EXPECT_TRUE(&gsl::at(c_a, i) == &a[static_cast(i)]); } @@ -64,9 +62,7 @@ TEST(at_tests, std_array) std::abort(); }); - EXPECT_DEATH(gsl::at(a, -1), deathstring); EXPECT_DEATH(gsl::at(a, 4), deathstring); - EXPECT_DEATH(gsl::at(c_a, -1), deathstring); EXPECT_DEATH(gsl::at(c_a, 4), deathstring); } @@ -75,7 +71,7 @@ TEST(at_tests, std_vector) std::vector a = {1, 2, 3, 4}; const std::vector& c_a = a; - for (int i = 0; i < 4; ++i) { + for (std::size_t i = 0; i < 4; ++i) { EXPECT_TRUE(&gsl::at(a, i) == &a[static_cast(i)]); EXPECT_TRUE(&gsl::at(c_a, i) == &a[static_cast(i)]); } @@ -85,9 +81,7 @@ TEST(at_tests, std_vector) std::abort(); }); - EXPECT_DEATH(gsl::at(a, -1), deathstring); EXPECT_DEATH(gsl::at(a, 4), deathstring); - EXPECT_DEATH(gsl::at(c_a, -1), deathstring); EXPECT_DEATH(gsl::at(c_a, 4), deathstring); } @@ -96,8 +90,8 @@ TEST(at_tests, InitializerList) const std::initializer_list a = {1, 2, 3, 4}; for (int i = 0; i < 4; ++i) { - EXPECT_TRUE(gsl::at(a, i) == i + 1); - EXPECT_TRUE(gsl::at({1, 2, 3, 4}, i) == i + 1); + EXPECT_TRUE(gsl::at(a, static_cast(i)) == i + 1); + EXPECT_TRUE(gsl::at({1, 2, 3, 4}, static_cast(i)) == i + 1); } std::set_terminate([] { @@ -105,9 +99,7 @@ TEST(at_tests, InitializerList) std::abort(); }); - EXPECT_DEATH(gsl::at(a, -1), deathstring); EXPECT_DEATH(gsl::at(a, 4), deathstring); - EXPECT_DEATH(gsl::at({1, 2, 3, 4}, -1), deathstring); EXPECT_DEATH(gsl::at({1, 2, 3, 4}, 4), deathstring); } @@ -120,12 +112,12 @@ static constexpr bool test_constexpr() const std::array& c_a2 = a2; for (int i = 0; i < 4; ++i) { - if (&gsl::at(a1, i) != &a1[i]) return false; - if (&gsl::at(c_a1, i) != &a1[i]) return false; + if (&gsl::at(a1, static_cast(i)) != &a1[i]) return false; + if (&gsl::at(c_a1, static_cast(i)) != &a1[i]) return false; // requires C++17: // if (&gsl::at(a2, i) != &a2[static_cast(i)]) return false; - if (&gsl::at(c_a2, i) != &c_a2[static_cast(i)]) return false; - if (gsl::at({1, 2, 3, 4}, i) != i + 1) return false; + if (&gsl::at(c_a2, static_cast(i)) != &c_a2[static_cast(i)]) return false; + if (gsl::at({1, 2, 3, 4}, static_cast(i)) != i + 1) return false; } return true; diff --git a/tests/span_tests.cpp b/tests/span_tests.cpp index 99ee0d8..ce10325 100644 --- a/tests/span_tests.cpp +++ b/tests/span_tests.cpp @@ -25,7 +25,7 @@ #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 @@ -161,11 +161,7 @@ TEST(span_test, from_pointer_length_constructor) EXPECT_TRUE(s.data() == &arr[0]); EXPECT_TRUE(s.empty() == (i == 0)); for (std::size_t j = 0; j < i; ++j) - { EXPECT_TRUE(arr[j] == s[j]); - EXPECT_TRUE(arr[j] == s.at(j)); - EXPECT_TRUE(arr[j] == s(j)); - } } { span s = {&arr[i], 4 - i}; @@ -174,11 +170,7 @@ TEST(span_test, from_pointer_length_constructor) EXPECT_TRUE(s.empty() == ((4 - i) == 0)); for (std::size_t 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)); - } } } } @@ -976,52 +968,6 @@ TEST(span_test, from_array_constructor) } } - 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); - } - } - TEST(span_test, iterator_default_init) { span::iterator it1; @@ -1093,8 +1039,8 @@ TEST(span_test, from_array_constructor) int a[] = {1, 2, 3, 4}; span s{a}; - EXPECT_TRUE((std::is_same::value)); - EXPECT_TRUE(s.size() == ssize(s)); + EXPECT_FALSE((std::is_same::value)); + EXPECT_TRUE(s.size() == static_cast(ssize(s))); } TEST(span_test, iterator_comparisons) diff --git a/tests/utils_tests.cpp b/tests/utils_tests.cpp index b6b5fc9..78bf59d 100644 --- a/tests/utils_tests.cpp +++ b/tests/utils_tests.cpp @@ -23,6 +23,7 @@ #include // for numeric_limits #include // for uint32_t, int32_t #include // for is_same +#include // for std::size_t using namespace gsl; @@ -37,7 +38,7 @@ void g() { j += 1; } TEST(utils_tests, sanity_check_for_gsl_index_typedef) { - static_assert(std::is_same::value, + static_assert(std::is_same::value, "gsl::index represents wrong arithmetic type"); } From 5cf1610cfe10ca083dd9eaf14cf9a12f2cb63692 Mon Sep 17 00:00:00 2001 From: "Jordan Maples [MSFT]" <49793787+JordanMaples@users.noreply.github.com> Date: Wed, 5 Feb 2020 12:58:49 -0800 Subject: [PATCH 26/45] prevent overflow in size_bytes. fix compilation issue for clang 3.6 and 3.7 --- include/gsl/span | 20 ++++++++++++-------- tests/span_tests.cpp | 29 ++++++++++++++++++++++++++++- 2 files changed, 40 insertions(+), 9 deletions(-) diff --git a/include/gsl/span b/include/gsl/span index 548587b..fbb3758 100644 --- a/include/gsl/span +++ b/include/gsl/span @@ -163,7 +163,7 @@ namespace details constexpr span_iterator operator++(int) noexcept { - auto ret{*this}; + span_iterator ret = {*this}; ++*this; return ret; } @@ -178,7 +178,7 @@ namespace details constexpr span_iterator operator--(int) noexcept { - auto ret{*this}; + span_iterator ret = {*this}; --*this; return ret; } @@ -194,7 +194,7 @@ namespace details constexpr span_iterator operator+(const difference_type n) const noexcept { - auto ret{*this}; + span_iterator ret = {*this}; return ret += n; } @@ -215,7 +215,7 @@ namespace details constexpr span_iterator operator-(const difference_type n) const noexcept { - auto ret{*this}; + span_iterator ret = {*this}; return ret -= n; } @@ -238,7 +238,8 @@ namespace details std::enable_if_t, value_type>::value, int> = 0> constexpr bool operator==(const span_iterator& rhs) const noexcept { - return begin_ == rhs.begin_ && end_ == rhs.end_ && current_ == rhs.current_; + Expects(begin_ == rhs.begin_ && end_ == rhs.end_); + return current_ == rhs.current_; } template < @@ -452,7 +453,7 @@ public: std::is_convertible::value && std::is_convertible().data())>::value>> - constexpr span(Container& cont) noexcept : span(cont.data(), narrow(cont.size())) + constexpr span(Container& cont) noexcept : span(cont.data(), cont.size()) {} template ().data())>::value>> constexpr span(const Container& cont) noexcept - : span(cont.data(), narrow(cont.size())) + : span(cont.data(), cont.size()) {} constexpr span(const span& other) noexcept = default; @@ -526,10 +527,13 @@ public: // [span.obs], span observers 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 diff --git a/tests/span_tests.cpp b/tests/span_tests.cpp index ce10325..c078f3a 100644 --- a/tests/span_tests.cpp +++ b/tests/span_tests.cpp @@ -1090,6 +1090,23 @@ 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; + EXPECT_DEATH(s.begin() == s2.begin(), deathstring); + EXPECT_DEATH(s.begin() <= s2.begin(), deathstring); + } + } + TEST(span_test, begin_end) { std::set_terminate([] { @@ -1425,8 +1442,12 @@ TEST(span_test, from_array_constructor) 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); @@ -1451,6 +1472,12 @@ 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) From 432be4852c4cd3807e26f90904e3a4cb397fee3a Mon Sep 17 00:00:00 2001 From: "Jordan Maples [MSFT]" <49793787+JordanMaples@users.noreply.github.com> Date: Wed, 5 Feb 2020 13:59:48 -0800 Subject: [PATCH 27/45] captureing result of iterator comparisons to address -Wunused-comparison --- tests/span_tests.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/span_tests.cpp b/tests/span_tests.cpp index c078f3a..9dbfb42 100644 --- a/tests/span_tests.cpp +++ b/tests/span_tests.cpp @@ -1102,8 +1102,8 @@ TEST(span_test, from_array_constructor) { span s = a; span s2 = b; - EXPECT_DEATH(s.begin() == s2.begin(), deathstring); - EXPECT_DEATH(s.begin() <= s2.begin(), deathstring); + EXPECT_DEATH(bool _ = (s.begin() == s2.begin()), deathstring); + EXPECT_DEATH(bool _ = (s.begin() <= s2.begin()), deathstring); } } From 7fcc142ffc9c73c891ca96ff3d84c17a03e6d230 Mon Sep 17 00:00:00 2001 From: "Jordan Maples [MSFT]" <49793787+JordanMaples@users.noreply.github.com> Date: Wed, 5 Feb 2020 14:32:08 -0800 Subject: [PATCH 28/45] addressing travis errors --- include/gsl/span | 8 ++++---- tests/span_tests.cpp | 9 +++++++-- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/include/gsl/span b/include/gsl/span index fbb3758..f8dd4a0 100644 --- a/include/gsl/span +++ b/include/gsl/span @@ -163,7 +163,7 @@ namespace details constexpr span_iterator operator++(int) noexcept { - span_iterator ret = {*this}; + auto ret{*this}; ++*this; return ret; } @@ -178,7 +178,7 @@ namespace details constexpr span_iterator operator--(int) noexcept { - span_iterator ret = {*this}; + auto ret{*this}; --*this; return ret; } @@ -194,7 +194,7 @@ namespace details constexpr span_iterator operator+(const difference_type n) const noexcept { - span_iterator ret = {*this}; + auto ret{*this}; return ret += n; } @@ -215,7 +215,7 @@ namespace details constexpr span_iterator operator-(const difference_type n) const noexcept { - span_iterator ret = {*this}; + auto ret{*this}; return ret -= n; } diff --git a/tests/span_tests.cpp b/tests/span_tests.cpp index 9dbfb42..c1dbbef 100644 --- a/tests/span_tests.cpp +++ b/tests/span_tests.cpp @@ -1102,8 +1102,13 @@ TEST(span_test, from_array_constructor) { span s = a; span s2 = b; - EXPECT_DEATH(bool _ = (s.begin() == s2.begin()), deathstring); - EXPECT_DEATH(bool _ = (s.begin() <= s2.begin()), deathstring); +#if (__cplusplus > 201402L) + EXPECT_DEATH([[maybe_unused]] s.begin() == s2.begin(), deathstring); + EXPECT_DEATH([[maybe_unused]] s.begin() <= s2.begin(), deathstring); +#else + EXPECT_DEATH(s.begin() == s2.begin(), deathstring); + EXPECT_DEATH(s.begin() <= s2.begin(), deathstring); +#endif } } From ff5f7973a28fc360bfd34af90486d784e48bc384 Mon Sep 17 00:00:00 2001 From: "Jordan Maples [MSFT]" <49793787+JordanMaples@users.noreply.github.com> Date: Wed, 5 Feb 2020 14:36:34 -0800 Subject: [PATCH 29/45] remove brackets around this deref for span_iterator operators --- include/gsl/span | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/gsl/span b/include/gsl/span index f8dd4a0..ecbca5d 100644 --- a/include/gsl/span +++ b/include/gsl/span @@ -163,7 +163,7 @@ namespace details constexpr span_iterator operator++(int) noexcept { - auto ret{*this}; + span_iterator ret = *this; ++*this; return ret; } @@ -178,7 +178,7 @@ namespace details constexpr span_iterator operator--(int) noexcept { - auto ret{*this}; + span_iterator ret = *this; --*this; return ret; } @@ -194,7 +194,7 @@ namespace details constexpr span_iterator operator+(const difference_type n) const noexcept { - auto ret{*this}; + span_iterator ret = *this; return ret += n; } @@ -215,7 +215,7 @@ namespace details constexpr span_iterator operator-(const difference_type n) const noexcept { - auto ret{*this}; + span_iterator ret = *this; return ret -= n; } From 45f016d96fe4bdc4c56d521509b88991f667c619 Mon Sep 17 00:00:00 2001 From: "Jordan Maples [MSFT]" <49793787+JordanMaples@users.noreply.github.com> Date: Wed, 5 Feb 2020 14:41:41 -0800 Subject: [PATCH 30/45] add back capture variable for comparison in span_test --- tests/span_tests.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/span_tests.cpp b/tests/span_tests.cpp index c1dbbef..5d9c18b 100644 --- a/tests/span_tests.cpp +++ b/tests/span_tests.cpp @@ -1103,11 +1103,11 @@ TEST(span_test, from_array_constructor) span s = a; span s2 = b; #if (__cplusplus > 201402L) - EXPECT_DEATH([[maybe_unused]] s.begin() == s2.begin(), deathstring); - EXPECT_DEATH([[maybe_unused]] s.begin() <= s2.begin(), deathstring); + EXPECT_DEATH([[maybe_unused]] bool _ = (s.begin() == s2.begin()), deathstring); + EXPECT_DEATH([[maybe_unused]] bool _ = (s.begin() <= s2.begin()), deathstring); #else - EXPECT_DEATH(s.begin() == s2.begin(), deathstring); - EXPECT_DEATH(s.begin() <= s2.begin(), deathstring); + EXPECT_DEATH(bool _ = (s.begin() == s2.begin()), deathstring); + EXPECT_DEATH(bool _ = (s.begin() <= s2.begin()), deathstring); #endif } } From 3b9d15f49fe043d42b2715dc5041f23ed7f56c5c Mon Sep 17 00:00:00 2001 From: "Jordan Maples [MSFT]" <49793787+JordanMaples@users.noreply.github.com> Date: Wed, 5 Feb 2020 17:02:23 -0800 Subject: [PATCH 31/45] reverting changes to gsl::index --- include/gsl/gsl_util | 13 +++++++------ tests/at_tests.cpp | 26 +++++++++++++++++--------- tests/utils_tests.cpp | 2 +- 3 files changed, 25 insertions(+), 16 deletions(-) diff --git a/include/gsl/gsl_util b/include/gsl/gsl_util index 53141e6..d1f7f33 100644 --- a/include/gsl/gsl_util +++ b/include/gsl/gsl_util @@ -49,7 +49,7 @@ namespace gsl // // index type for all container indexes/subscripts/sizes -using index = std::size_t; +using index = std::ptrdiff_t; // final_action allows you to ensure something gets run at the end of a scope template @@ -129,8 +129,8 @@ GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute constexpr T& at(T (&arr)[N], const index i) { - Expects(i >= 0 && i < N); - return arr[i]; + Expects(i >= 0 && i < narrow_cast(N)); + return arr[narrow_cast(i)]; } template @@ -138,15 +138,16 @@ GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute constexpr auto at(Cont& cont, const index i) -> decltype(cont[cont.size()]) { - Expects(i >= 0 && i < cont.size()); - return cont[i]; + Expects(i >= 0 && i < narrow_cast(cont.size())); + using size_type = decltype(cont.size()); + return cont[narrow_cast(i)]; } template GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute constexpr T at(const std::initializer_list cont, const index i) { - Expects(i >= 0 && i < cont.size()); + Expects(i >= 0 && i < narrow_cast(cont.size())); return *(cont.begin() + i); } diff --git a/tests/at_tests.cpp b/tests/at_tests.cpp index 0580301..be2c7b8 100644 --- a/tests/at_tests.cpp +++ b/tests/at_tests.cpp @@ -33,7 +33,7 @@ TEST(at_tests, static_array) int a[4] = {1, 2, 3, 4}; const int(&c_a)[4] = a; - for (std::size_t i = 0; i < 4; ++i) { + for (int i = 0; i < 4; ++i) { EXPECT_TRUE(&gsl::at(a, i) == &a[i]); EXPECT_TRUE(&gsl::at(c_a, i) == &a[i]); } @@ -43,7 +43,9 @@ TEST(at_tests, static_array) std::abort(); }); + EXPECT_DEATH(gsl::at(a, -1), deathstring); EXPECT_DEATH(gsl::at(a, 4), deathstring); + EXPECT_DEATH(gsl::at(c_a, -1), deathstring); EXPECT_DEATH(gsl::at(c_a, 4), deathstring); } @@ -52,7 +54,7 @@ TEST(at_tests, std_array) std::array a = {1, 2, 3, 4}; const std::array& c_a = a; - for (std::size_t i = 0; i < 4; ++i) { + for (int i = 0; i < 4; ++i) { EXPECT_TRUE(&gsl::at(a, i) == &a[static_cast(i)]); EXPECT_TRUE(&gsl::at(c_a, i) == &a[static_cast(i)]); } @@ -62,7 +64,9 @@ TEST(at_tests, std_array) std::abort(); }); + EXPECT_DEATH(gsl::at(a, -1), deathstring); EXPECT_DEATH(gsl::at(a, 4), deathstring); + EXPECT_DEATH(gsl::at(c_a, -1), deathstring); EXPECT_DEATH(gsl::at(c_a, 4), deathstring); } @@ -71,7 +75,7 @@ TEST(at_tests, std_vector) std::vector a = {1, 2, 3, 4}; const std::vector& c_a = a; - for (std::size_t i = 0; i < 4; ++i) { + for (int i = 0; i < 4; ++i) { EXPECT_TRUE(&gsl::at(a, i) == &a[static_cast(i)]); EXPECT_TRUE(&gsl::at(c_a, i) == &a[static_cast(i)]); } @@ -81,7 +85,9 @@ TEST(at_tests, std_vector) std::abort(); }); + EXPECT_DEATH(gsl::at(a, -1), deathstring); EXPECT_DEATH(gsl::at(a, 4), deathstring); + EXPECT_DEATH(gsl::at(c_a, -1), deathstring); EXPECT_DEATH(gsl::at(c_a, 4), deathstring); } @@ -90,8 +96,8 @@ TEST(at_tests, InitializerList) const std::initializer_list a = {1, 2, 3, 4}; for (int i = 0; i < 4; ++i) { - EXPECT_TRUE(gsl::at(a, static_cast(i)) == i + 1); - EXPECT_TRUE(gsl::at({1, 2, 3, 4}, static_cast(i)) == i + 1); + EXPECT_TRUE(gsl::at(a, i) == i + 1); + EXPECT_TRUE(gsl::at({1, 2, 3, 4}, i) == i + 1); } std::set_terminate([] { @@ -99,7 +105,9 @@ TEST(at_tests, InitializerList) std::abort(); }); + EXPECT_DEATH(gsl::at(a, -1), deathstring); EXPECT_DEATH(gsl::at(a, 4), deathstring); + EXPECT_DEATH(gsl::at({1, 2, 3, 4}, -1), deathstring); EXPECT_DEATH(gsl::at({1, 2, 3, 4}, 4), deathstring); } @@ -112,12 +120,12 @@ static constexpr bool test_constexpr() const std::array& c_a2 = a2; for (int i = 0; i < 4; ++i) { - if (&gsl::at(a1, static_cast(i)) != &a1[i]) return false; - if (&gsl::at(c_a1, static_cast(i)) != &a1[i]) return false; + if (&gsl::at(a1, i) != &a1[i]) return false; + if (&gsl::at(c_a1, i) != &a1[i]) return false; // requires C++17: // if (&gsl::at(a2, i) != &a2[static_cast(i)]) return false; - if (&gsl::at(c_a2, static_cast(i)) != &c_a2[static_cast(i)]) return false; - if (gsl::at({1, 2, 3, 4}, static_cast(i)) != i + 1) return false; + if (&gsl::at(c_a2, i) != &c_a2[static_cast(i)]) return false; + if (gsl::at({1, 2, 3, 4}, i) != i + 1) return false; } return true; diff --git a/tests/utils_tests.cpp b/tests/utils_tests.cpp index 78bf59d..1fb0fd2 100644 --- a/tests/utils_tests.cpp +++ b/tests/utils_tests.cpp @@ -38,7 +38,7 @@ void g() { j += 1; } TEST(utils_tests, sanity_check_for_gsl_index_typedef) { - static_assert(std::is_same::value, + static_assert(std::is_same::value, "gsl::index represents wrong arithmetic type"); } From a49ff1b8df978c1b80738cab3bb25b4140fa6424 Mon Sep 17 00:00:00 2001 From: "Jordan Maples [MSFT]" <49793787+JordanMaples@users.noreply.github.com> Date: Wed, 5 Feb 2020 17:12:31 -0800 Subject: [PATCH 32/45] update span specialization of at, change some tests back to int i with narrowing for the comparisons. --- include/gsl/span | 3 ++- tests/span_tests.cpp | 18 +++++++++--------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/include/gsl/span b/include/gsl/span index ecbca5d..b922576 100644 --- a/include/gsl/span +++ b/include/gsl/span @@ -806,7 +806,8 @@ template constexpr ElementType& at(span s, index i) { // No bounds checking here because it is done in span::operator[] called below - return s[i]; + Ensures(i >= 0); + return s[narrow_cast(i)]; } // [span.obs] Free observer functions diff --git a/tests/span_tests.cpp b/tests/span_tests.cpp index 5d9c18b..790cee0 100644 --- a/tests/span_tests.cpp +++ b/tests/span_tests.cpp @@ -153,24 +153,24 @@ TEST(span_test, from_pointer_length_constructor) int arr[4] = {1, 2, 3, 4}; { - for (std::size_t i = 0; i < 4; ++i) + 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 (std::size_t j = 0; j < i; ++j) - EXPECT_TRUE(arr[j] == s[j]); + for (int j = 0; j < i; ++j) + EXPECT_TRUE(arr[j] == s[narrow_cast(j)]); } { - span s = {&arr[i], 4 - 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 (std::size_t j = 0; j < 4 - i; ++j) - EXPECT_TRUE(arr[j + i] == s[j]); + for (int j = 0; j < 4 - i; ++j) + EXPECT_TRUE(arr[j + i] == s[narrow_cast(j)]); } } } From 377b2db537f4f0d766f2a66d7a27033f62b19e19 Mon Sep 17 00:00:00 2001 From: "Jordan Maples [MSFT]" <49793787+JordanMaples@users.noreply.github.com> Date: Fri, 7 Feb 2020 14:09:57 -0800 Subject: [PATCH 33/45] almost parity with std::span --- include/gsl/span | 107 ++++++++++++++++++++++++++++++++----------- tests/span_tests.cpp | 16 ++++++- 2 files changed, 94 insertions(+), 29 deletions(-) diff --git a/include/gsl/span b/include/gsl/span index b922576..6cfc91c 100644 --- a/include/gsl/span +++ b/include/gsl/span @@ -111,8 +111,7 @@ namespace details template struct is_allowed_extent_conversion - : public std::integral_constant + : public std::integral_constant { }; @@ -301,7 +300,9 @@ namespace details 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 @@ -316,7 +317,9 @@ 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 @@ -392,7 +395,9 @@ public: using value_type = std::remove_cv_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; @@ -410,38 +415,48 @@ public: // [span.cons], span constructors, copy, assignment, and destructor template " SFINAE, - // since "std::enable_if_t" is ill-formed when Extent is greater than 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 || Extent == 0 || Extent == dynamic_extent)>> constexpr span() noexcept : storage_(nullptr, details::extent_type<0>()) {} - constexpr span(pointer ptr, size_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, static_cast(std::distance(firstElem, lastElem))) - {} + { + if (Extent != dynamic_extent) { Expects(lastElem - firstElem == Extent); } + } template constexpr span(element_type (&arr)[N]) noexcept : storage_(KnownNotNull{std::addressof(arr[0])}, details::extent_type()) {} - template 0)>> - constexpr span(std::array, N>& arr) noexcept + template = 0> + constexpr span(std::array& arr) noexcept : storage_(KnownNotNull{arr.data()}, details::extent_type()) {} - constexpr span(std::array, 0>&) noexcept + template ::value), + int> = 0> + constexpr span(const std::array& arr) noexcept + : storage_(KnownNotNull{arr.data()}, details::extent_type()) + {} + + constexpr span(std::array&) noexcept : storage_(static_cast(nullptr), details::extent_type<0>()) {} - template 0)>> - constexpr span(const std::array, N>& arr) noexcept - : storage_(KnownNotNull{arr.data()}, details::extent_type()) - {} - - constexpr span(const std::array, 0>&) noexcept + constexpr span(const std::array&) noexcept : storage_(static_cast(nullptr), details::extent_type<0>()) {} @@ -451,8 +466,8 @@ public: class = std::enable_if_t< !details::is_span::value && !details::is_std_array::value && std::is_convertible::value && - std::is_convertible().data())>::value>> + std::is_convertible::value && + std::is_convertible().data()), pointer>::value>> constexpr span(Container& cont) noexcept : span(cont.data(), cont.size()) {} @@ -460,10 +475,8 @@ public: class = std::enable_if_t< std::is_const::value && !details::is_span::value && std::is_convertible::value && - std::is_convertible().data())>::value>> - constexpr span(const Container& cont) noexcept - : span(cont.data(), cont.size()) + std::is_convertible().data()), pointer>::value>> + constexpr span(const Container& cont) noexcept : span(cont.data(), cont.size()) {} constexpr span(const span& other) noexcept = default; @@ -489,16 +502,20 @@ public: } template + // clang-format off GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute - constexpr span last() const noexcept + // clang-format on + constexpr span last() const noexcept { Expects(size() >= Count); return {data() + (size() - Count), Count}; } template + // clang-format off GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute - constexpr auto subspan() const noexcept -> + // clang-format on + constexpr auto subspan() const noexcept -> typename details::calculate_subspan_type::type { Expects((size() >= Offset) && (Count == dynamic_extent || (Count <= size() - Offset))); @@ -537,7 +554,9 @@ public: constexpr bool empty() const noexcept { return size() == 0; } // [span.elem], span element access + // clang-format off GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute + // clang-format on constexpr reference operator[](size_type idx) const noexcept { Expects(idx < size()); @@ -602,7 +621,9 @@ 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 @@ -662,7 +683,9 @@ private: return tmp.subspan(offset, count); } + // clang-format off GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute + // clang-format on span make_subspan(size_type offset, size_type count, subspan_selector) const { @@ -675,6 +698,20 @@ private: } }; +#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::size_type span::extent; @@ -742,16 +779,32 @@ 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>> + std::enable_if_t::value, int> = 0> span::value> +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()}; +} + +template ::value, int> = 0> +[[deprecated( + "use as_writable_bytes")]] span::value> as_writeable_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()}; } @@ -759,8 +812,7 @@ as_writeable_bytes(span s) noexcept // make_span() - Utility functions for creating spans // template -constexpr span make_span(ElementType* ptr, - typename span::size_type count) +constexpr span make_span(ElementType* ptr, typename span::size_type count) { return span(ptr, count); } @@ -812,8 +864,7 @@ constexpr ElementType& at(span s, index i) // [span.obs] Free observer functions template -constexpr std::ptrdiff_t -ssize(const span& s) noexcept +constexpr std::ptrdiff_t ssize(const span& s) noexcept { return static_cast(s.size()); } diff --git a/tests/span_tests.cpp b/tests/span_tests.cpp index 790cee0..8c5ac0d 100644 --- a/tests/span_tests.cpp +++ b/tests/span_tests.cpp @@ -1551,11 +1551,15 @@ TEST(span_test, from_array_constructor) // even when done dynamically { span s = arr; + /* + // this now results in a compile-time error, rather than runtime. + // There is no suitable conversion from dynamic span to fixed span. auto f = [&]() { const span s2 = s; static_cast(s2); }; EXPECT_DEATH(f(), deathstring); + */ } // but doing so explicitly is ok @@ -1570,12 +1574,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}; @@ -1597,12 +1608,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) From b81d6e40e13708a6019ff9758db263c2f385ed80 Mon Sep 17 00:00:00 2001 From: "Jordan Maples [MSFT]" <49793787+JordanMaples@users.noreply.github.com> Date: Fri, 7 Feb 2020 14:15:44 -0800 Subject: [PATCH 34/45] constexpr the make_subspan calls. --- include/gsl/span | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/gsl/span b/include/gsl/span index 6cfc91c..445826c 100644 --- a/include/gsl/span +++ b/include/gsl/span @@ -676,7 +676,7 @@ private: }; template - span make_subspan(size_type offset, size_type count, + constexpr span make_subspan(size_type offset, size_type count, subspan_selector) const { const span tmp(*this); @@ -686,7 +686,7 @@ private: // clang-format off GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute // clang-format on - span make_subspan(size_type offset, size_type count, + constexpr span make_subspan(size_type offset, size_type count, subspan_selector) const { Expects(size() >= offset); From d8fa68c4a589e6461c4bb2a58d5ccc1c1075b5ef Mon Sep 17 00:00:00 2001 From: "Jordan Maples [MSFT]" <49793787+JordanMaples@users.noreply.github.com> Date: Fri, 7 Feb 2020 14:40:09 -0800 Subject: [PATCH 35/45] address build failures --- include/gsl/span | 2 +- tests/span_tests.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/gsl/span b/include/gsl/span index 445826c..20f4237 100644 --- a/include/gsl/span +++ b/include/gsl/span @@ -430,7 +430,7 @@ public: constexpr span(pointer firstElem, pointer lastElem) noexcept : storage_(firstElem, static_cast(std::distance(firstElem, lastElem))) { - if (Extent != dynamic_extent) { Expects(lastElem - firstElem == Extent); } + if (Extent != dynamic_extent) { Expects(lastElem - firstElem == static_cast(Extent)); } } template diff --git a/tests/span_tests.cpp b/tests/span_tests.cpp index 8c5ac0d..1f5020b 100644 --- a/tests/span_tests.cpp +++ b/tests/span_tests.cpp @@ -1550,10 +1550,10 @@ TEST(span_test, from_array_constructor) // even when done dynamically { - span s = arr; /* // 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); From dd78144c2ebcc52cebb3c336743d04ee04968f9f Mon Sep 17 00:00:00 2001 From: "Jordan Maples [MSFT]" <49793787+JordanMaples@users.noreply.github.com> Date: Mon, 10 Feb 2020 13:17:22 -0800 Subject: [PATCH 36/45] msvc and gcc work locally --- include/gsl/span | 37 +++++++++++++++++-------------------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/include/gsl/span b/include/gsl/span index 20f4237..62591df 100644 --- a/include/gsl/span +++ b/include/gsl/span @@ -418,7 +418,8 @@ public: // "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 || Extent == 0 || Extent == dynamic_extent)>> + class = std::enable_if_t<(Dependent || + details::is_allowed_extent_conversion<0, Extent>::value)>> constexpr span() noexcept : storage_(nullptr, details::extent_type<0>()) {} @@ -430,36 +431,31 @@ public: constexpr span(pointer firstElem, pointer lastElem) noexcept : storage_(firstElem, static_cast(std::distance(firstElem, lastElem))) { - if (Extent != dynamic_extent) { Expects(lastElem - firstElem == static_cast(Extent)); } + 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()) {} - template = 0> - constexpr span(std::array& arr) noexcept + template ::value, int> = 0> + constexpr span(std::array& arr) noexcept : storage_(KnownNotNull{arr.data()}, details::extent_type()) {} - template ::value), + 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(std::array&) noexcept - : storage_(static_cast(nullptr), details::extent_type<0>()) - {} - - constexpr span(const std::array&) noexcept - : storage_(static_cast(nullptr), details::extent_type<0>()) - {} - // NB: the SFINAE here uses .data() as a incomplete/imperfect proxy for the requirement // on Container to be a contiguous sequence container. template ::value && !details::is_span::value && + !details::is_std_array::value && std::is_convertible::value && std::is_convertible().data()), pointer>::value>> constexpr span(const Container& cont) noexcept : span(cont.data(), cont.size()) @@ -677,7 +674,7 @@ private: template constexpr span make_subspan(size_type offset, size_type count, - subspan_selector) const + subspan_selector) const { const span tmp(*this); return tmp.subspan(offset, count); @@ -686,8 +683,8 @@ private: // clang-format off GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute // clang-format on - constexpr span make_subspan(size_type offset, size_type count, - subspan_selector) const + constexpr span + make_subspan(size_type offset, size_type count, subspan_selector) const { Expects(size() >= offset); From cce6ee563eb2047238f57c62afe4e44a5ee8ce8a Mon Sep 17 00:00:00 2001 From: "Jordan Maples [MSFT]" <49793787+JordanMaples@users.noreply.github.com> Date: Mon, 10 Feb 2020 17:09:58 -0800 Subject: [PATCH 37/45] address issue with v140 toolset --- include/gsl/span | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/include/gsl/span b/include/gsl/span index 62591df..6c2b4de 100644 --- a/include/gsl/span +++ b/include/gsl/span @@ -71,7 +71,11 @@ namespace gsl { // [views.constants], constants +#if (defined(GSL_USE_STATIC_CONSTEXPR_WORKAROUND)) +constexpr const std::size_t dynamic_extent = static_cast(-1); +#else constexpr std::size_t dynamic_extent = static_cast(-1); +#endif template class span; @@ -134,6 +138,12 @@ namespace details #ifdef _MSC_VER using _Unchecked_type = pointer; #endif + constexpr span_iterator() = default; + + constexpr span_iterator(pointer begin, pointer end, pointer current) + : begin_(begin), end_(end), current_(current) + {} + constexpr operator span_iterator() const noexcept { return {begin_, end_, current_}; @@ -494,6 +504,7 @@ public: template constexpr span first() const noexcept { + Expects(Count != dynamic_extent); Expects(Count <= size()); return {data(), Count}; } @@ -504,6 +515,7 @@ public: // clang-format on constexpr span last() const noexcept { + Expects(Count != dynamic_extent); Expects(size() >= Count); return {data() + (size() - Count), Count}; } From 926aaeca5618931097a7626ffe4a0f87623e1cd8 Mon Sep 17 00:00:00 2001 From: "Jordan Maples [MSFT]" <49793787+JordanMaples@users.noreply.github.com> Date: Tue, 11 Feb 2020 16:36:07 -0800 Subject: [PATCH 38/45] reviewed the pr in its entirety and made some slight modifications. Removed all members and fields marked as deprecated. --- include/gsl/span | 26 ++++---------------------- include/gsl/string_span | 2 +- tests/span_tests.cpp | 8 ++++---- tests/string_span_tests.cpp | 4 ++-- 4 files changed, 11 insertions(+), 29 deletions(-) diff --git a/include/gsl/span b/include/gsl/span index 6c2b4de..8f73b1c 100644 --- a/include/gsl/span +++ b/include/gsl/span @@ -71,11 +71,7 @@ namespace gsl { // [views.constants], constants -#if (defined(GSL_USE_STATIC_CONSTEXPR_WORKAROUND)) constexpr const std::size_t dynamic_extent = static_cast(-1); -#else -constexpr std::size_t dynamic_extent = static_cast(-1); -#endif template class span; @@ -137,7 +133,7 @@ namespace details #ifdef _MSC_VER using _Unchecked_type = pointer; -#endif +#endif // _MSC_VER constexpr span_iterator() = default; constexpr span_iterator(pointer begin, pointer end, pointer current) @@ -348,14 +344,14 @@ namespace details public: using size_type = std::size_t; - static_assert(Ext != dynamic_extent, "A fixed-size span must be >= 0 in size."); + static_assert(Ext != dynamic_extent, "A fixed-size span must not have size == dynamic_extent"); constexpr extent_type() noexcept {} 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); } @@ -415,8 +411,6 @@ public: using reverse_iterator = std::reverse_iterator; using const_reverse_iterator = std::reverse_iterator; - using index_type [[deprecated("use size_type instead of index_type")]] = size_type; - #if defined(GSL_USE_STATIC_CONSTEXPR_WORKAROUND) static constexpr const size_type extent{Extent}; #else @@ -805,18 +799,6 @@ as_writable_bytes(span s) noexcept return {reinterpret_cast(s.data()), s.size_bytes()}; } -template ::value, int> = 0> -[[deprecated( - "use as_writable_bytes")]] span::value> -as_writeable_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 // @@ -868,7 +850,7 @@ 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)]; + return s[static_cast(i)]; } // [span.obs] Free observer functions diff --git a/include/gsl/string_span b/include/gsl/string_span index 27b8977..cc0588e 100644 --- a/include/gsl/string_span +++ b/include/gsl/string_span @@ -381,7 +381,7 @@ as_bytes(basic_string_span s) noexcept 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()}; diff --git a/tests/span_tests.cpp b/tests/span_tests.cpp index 1f5020b..ab437a5 100644 --- a/tests/span_tests.cpp +++ b/tests/span_tests.cpp @@ -1485,7 +1485,7 @@ TEST(span_test, from_array_constructor) } } - TEST(span_test, as_writeable_bytes) + TEST(span_test, as_writable_bytes) { int a[] = {1, 2, 3, 4}; @@ -1494,7 +1494,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 @@ -1502,7 +1502,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); @@ -1512,7 +1512,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()); } diff --git a/tests/string_span_tests.cpp b/tests/string_span_tests.cpp index c1f8cf4..7a9f7fb 100644 --- a/tests/string_span_tests.cpp +++ b/tests/string_span_tests.cpp @@ -1206,12 +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()); } From 41ae38f197a8b1565352a156bc0e5fa9772cec25 Mon Sep 17 00:00:00 2001 From: "Jordan Maples [MSFT]" <49793787+JordanMaples@users.noreply.github.com> Date: Fri, 14 Feb 2020 15:24:46 -0800 Subject: [PATCH 39/45] addressing a few more comments and adding gsl-std span compatibility tests --- include/gsl/span | 15 +- tests/CMakeLists.txt | 1 + tests/span_compatibility_tests.cpp | 1066 ++++++++++++++++++++++++++++ tests/span_tests.cpp | 9 +- tests/utils_tests.cpp | 2 +- 5 files changed, 1080 insertions(+), 13 deletions(-) create mode 100644 tests/span_compatibility_tests.cpp diff --git a/include/gsl/span b/include/gsl/span index 8f73b1c..cffe043 100644 --- a/include/gsl/span +++ b/include/gsl/span @@ -105,19 +105,19 @@ namespace details }; template - struct is_std_array : public is_std_array_oracle> + struct is_std_array : is_std_array_oracle> { }; 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> { }; @@ -460,13 +460,12 @@ public: : storage_(KnownNotNull{arr.data()}, details::extent_type()) {} - // 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::value && std::is_convertible().data()), pointer>::value>> constexpr span(Container& cont) noexcept : span(cont.data(), cont.size()) {} @@ -671,7 +670,7 @@ private: // The rest is needed to remove unnecessary null check // in subspans and constructors from arrays - constexpr span(KnownNotNull ptr, size_type count) : storage_(ptr, count) {} + constexpr span(KnownNotNull ptr, size_type count) noexcept : storage_(ptr, count) {} template class subspan_selector @@ -680,7 +679,7 @@ private: template constexpr span make_subspan(size_type offset, size_type count, - subspan_selector) const + subspan_selector) const noexcept { const span tmp(*this); return tmp.subspan(offset, count); @@ -690,7 +689,7 @@ private: GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute // clang-format on constexpr span - make_subspan(size_type offset, size_type count, subspan_selector) const + make_subspan(size_type offset, size_type count, subspan_selector) const noexcept { Expects(size() >= offset); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 3a6163c..38dbb85 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -153,6 +153,7 @@ function(add_gsl_test name) endfunction() add_gsl_test(span_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) diff --git a/tests/span_compatibility_tests.cpp b/tests/span_compatibility_tests.cpp new file mode 100644 index 0000000..cdf0bff --- /dev/null +++ b/tests/span_compatibility_tests.cpp @@ -0,0 +1,1066 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// 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 + +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"); + +template +constexpr bool AsWritableBytesCompilesFor = false; + +template +constexpr bool AsWritableBytesCompilesFor()))>> = + true; + +TEST(span_test, std_span_compatibilty_assertion_tests) +{ + int arr[3]{10, 20, 30}; + std::array stl{{100, 200, 300}}; + + { + gsl::span sp_dyn; + assert(sp_dyn.data() == nullptr); + assert(sp_dyn.size() == 0); + assert(sp_dyn.empty()); + } + { + gsl::span sp_zero; + assert(sp_zero.data() == nullptr); + assert(sp_zero.size() == 0); + assert(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))"); + + static_assert(AsWritableBytesCompilesFor>, + "AsWritableBytesCompilesFor>"); + static_assert(AsWritableBytesCompilesFor>, + "AsWritableBytesCompilesFor>"); + static_assert(!AsWritableBytesCompilesFor>, + "!AsWritableBytesCompilesFor>"); + static_assert(!AsWritableBytesCompilesFor>, + "!AsWritableBytesCompilesFor>"); + + 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, 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>"); diff --git a/tests/span_tests.cpp b/tests/span_tests.cpp index ab437a5..2c4a19c 100644 --- a/tests/span_tests.cpp +++ b/tests/span_tests.cpp @@ -29,6 +29,7 @@ #include // for string #include // for integral_constant<>::value, is_default_co... #include // for vector +#include using namespace std; using namespace gsl; @@ -1021,11 +1022,11 @@ TEST(span_test, from_array_constructor) 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.begin() == std::begin(s)); + EXPECT_TRUE(s.end() == std::end(s)); - EXPECT_TRUE(s.cbegin() == cbegin(s)); - EXPECT_TRUE(s.cend() == cend(s)); + EXPECT_TRUE(s.cbegin() == std::cbegin(s)); + EXPECT_TRUE(s.cend() == std::cend(s)); EXPECT_TRUE(s.rbegin() == rbegin(s)); EXPECT_TRUE(s.rend() == rend(s)); diff --git a/tests/utils_tests.cpp b/tests/utils_tests.cpp index 1fb0fd2..f7f7ce3 100644 --- a/tests/utils_tests.cpp +++ b/tests/utils_tests.cpp @@ -23,7 +23,7 @@ #include // for numeric_limits #include // for uint32_t, int32_t #include // for is_same -#include // for std::size_t +#include // for std::ptrdiff_t using namespace gsl; From 67a7f7eaef6481d9f929bef24839b05dfbbd7b5a Mon Sep 17 00:00:00 2001 From: "Jordan Maples [MSFT]" <49793787+JordanMaples@users.noreply.github.com> Date: Fri, 14 Feb 2020 15:44:58 -0800 Subject: [PATCH 40/45] errors in appveyor are indicating that AsWritableByesCompilersFor needs to be static. --- tests/span_compatibility_tests.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/span_compatibility_tests.cpp b/tests/span_compatibility_tests.cpp index cdf0bff..62793e7 100644 --- a/tests/span_compatibility_tests.cpp +++ b/tests/span_compatibility_tests.cpp @@ -42,10 +42,10 @@ static_assert(!std::is_convertible::value, "!std::is_convertible"); template -constexpr bool AsWritableBytesCompilesFor = false; +static constexpr bool AsWritableBytesCompilesFor = false; template -constexpr bool AsWritableBytesCompilesFor()))>> = +static constexpr bool AsWritableBytesCompilesFor()))>> = true; TEST(span_test, std_span_compatibilty_assertion_tests) From b6b1e9c3cf1200ad5d912d4bd63364286863cbfc Mon Sep 17 00:00:00 2001 From: jordan maples Date: Fri, 14 Feb 2020 16:13:21 -0800 Subject: [PATCH 41/45] assert -> expect_true --- tests/span_compatibility_tests.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/span_compatibility_tests.cpp b/tests/span_compatibility_tests.cpp index 62793e7..d4cde0c 100644 --- a/tests/span_compatibility_tests.cpp +++ b/tests/span_compatibility_tests.cpp @@ -48,22 +48,22 @@ template static constexpr bool AsWritableBytesCompilesFor()))>> = true; -TEST(span_test, std_span_compatibilty_assertion_tests) +TEST(span_compatibility_tests, assertion_tests) { int arr[3]{10, 20, 30}; std::array stl{{100, 200, 300}}; { gsl::span sp_dyn; - assert(sp_dyn.data() == nullptr); - assert(sp_dyn.size() == 0); - assert(sp_dyn.empty()); + EXPECT_TRUE(sp_dyn.data() == nullptr); + EXPECT_TRUE(sp_dyn.size() == 0); + EXPECT_TRUE(sp_dyn.empty()); } { gsl::span sp_zero; - assert(sp_zero.data() == nullptr); - assert(sp_zero.size() == 0); - assert(sp_zero.empty()); + 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); From 6b01a0488b1157a2c49805b85becd09e1fe84f57 Mon Sep 17 00:00:00 2001 From: "Jordan Maples [MSFT]" <49793787+JordanMaples@users.noreply.github.com> Date: Fri, 14 Feb 2020 16:25:25 -0800 Subject: [PATCH 42/45] Update span_compatibility_tests.cpp some fixes. --- tests/span_compatibility_tests.cpp | 35 ++++++++++++++++-------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/tests/span_compatibility_tests.cpp b/tests/span_compatibility_tests.cpp index d4cde0c..57a85e7 100644 --- a/tests/span_compatibility_tests.cpp +++ b/tests/span_compatibility_tests.cpp @@ -41,13 +41,6 @@ static_assert(std::is_convertible::value, "std::is_convertible< static_assert(!std::is_convertible::value, "!std::is_convertible"); -template -static constexpr bool AsWritableBytesCompilesFor = false; - -template -static constexpr bool AsWritableBytesCompilesFor()))>> = - true; - TEST(span_compatibility_tests, assertion_tests) { int arr[3]{10, 20, 30}; @@ -501,15 +494,6 @@ TEST(span_compatibility_tests, assertion_tests) 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))"); - static_assert(AsWritableBytesCompilesFor>, - "AsWritableBytesCompilesFor>"); - static_assert(AsWritableBytesCompilesFor>, - "AsWritableBytesCompilesFor>"); - static_assert(!AsWritableBytesCompilesFor>, - "!AsWritableBytesCompilesFor>"); - static_assert(!AsWritableBytesCompilesFor>, - "!AsWritableBytesCompilesFor>"); - auto sp_1 = as_bytes(sp_dyn); auto sp_2 = as_bytes(sp_nine); auto sp_3 = as_bytes(sp_const_dyn); @@ -1064,3 +1048,22 @@ static_assert(std::is_convertible&, gsl::span>::va static_assert(std::is_convertible&, gsl::span>::value, "std::is_convertible&, gsl::span>"); + + +#if __cplusplus >= 201703l +template +inline constexpr bool AsWritableBytesCompilesFor = false; + +template +inline constexpr bool AsWritableBytesCompilesFor()))>> = + true; + +static_assert(AsWritableBytesCompilesFor>, + "AsWritableBytesCompilesFor>"); +static_assert(AsWritableBytesCompilesFor>, + "AsWritableBytesCompilesFor>"); +static_assert(!AsWritableBytesCompilesFor>, + "!AsWritableBytesCompilesFor>"); +static_assert(!AsWritableBytesCompilesFor>, + "!AsWritableBytesCompilesFor>"); +#endif // __cplusplus >= 201703l From 8d6ca323fad94f22b0233d30fdf13228bcb5ccb0 Mon Sep 17 00:00:00 2001 From: "Jordan Maples [MSFT]" <49793787+JordanMaples@users.noreply.github.com> Date: Tue, 18 Feb 2020 10:13:03 -0800 Subject: [PATCH 43/45] GTest latest is breaking, rolling back to 1.10 until further investigation --- tests/CMakeLists.txt.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 "" From f4c608fd39fe8129dfb2ea5e737e2aea6baf4519 Mon Sep 17 00:00:00 2001 From: "Jordan Maples [MSFT]" <49793787+JordanMaples@users.noreply.github.com> Date: Tue, 18 Feb 2020 14:09:11 -0800 Subject: [PATCH 44/45] addressing comments --- include/gsl/span | 47 ++++++++++++++---------------- tests/span_compatibility_tests.cpp | 12 ++++---- 2 files changed, 29 insertions(+), 30 deletions(-) diff --git a/include/gsl/span b/include/gsl/span index cffe043..e3ea0db 100644 --- a/include/gsl/span +++ b/include/gsl/span @@ -25,7 +25,6 @@ #include // for array #include // for ptrdiff_t, size_t, nullptr_t #include // for reverse_iterator, distance, random_access_... -#include // for std::addressof #include #include // for enable_if_t, declval, is_convertible, inte... #include @@ -147,14 +146,14 @@ namespace details constexpr reference operator*() const noexcept { - Expects(begin_ && current_ && end_); + Expects(begin_ && end_); Expects(begin_ <= current_ && current_ < end_); return *current_; } constexpr pointer operator->() const noexcept { - Expects(begin_ && current_ && end_); + Expects(begin_ && end_); Expects(begin_ <= current_ && current_ < end_); return current_; } @@ -175,7 +174,7 @@ namespace details constexpr span_iterator& operator--() noexcept { - Expects(begin_ && current_ && end_); + Expects(begin_ && end_); Expects(begin_ < current_); --current_; return *this; @@ -346,7 +345,7 @@ namespace details static_assert(Ext != dynamic_extent, "A fixed-size span must not have size == dynamic_extent"); - constexpr extent_type() noexcept {} + constexpr extent_type() noexcept = default; template constexpr extent_type(extent_type ext) @@ -433,7 +432,7 @@ public: } constexpr span(pointer firstElem, pointer lastElem) noexcept - : storage_(firstElem, static_cast(std::distance(firstElem, lastElem))) + : storage_(firstElem, static_cast(lastElem - firstElem)) { if (Extent != dynamic_extent) { Expects(lastElem - firstElem == static_cast(Extent)); } @@ -442,7 +441,7 @@ public: 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 ::value && !details::is_std_array::value && - std::is_convertible::value && - std::is_convertible().data()), pointer>::value>> + std::is_pointer().data())>::value && + std::is_convertible().data())>(*)[], element_type(*)[]>::value>> constexpr span(Container& cont) noexcept : span(cont.data(), cont.size()) {} @@ -474,8 +473,8 @@ public: class = std::enable_if_t< std::is_const::value && !details::is_span::value && !details::is_std_array::value && - std::is_convertible::value && - std::is_convertible().data()), pointer>::value>> + std::is_pointer().data())>::value && + std::is_convertible().data())>(*)[], element_type(*)[]>::value>> constexpr span(const Container& cont) noexcept : span(cont.data(), cont.size()) {} @@ -497,7 +496,6 @@ public: template constexpr span first() const noexcept { - Expects(Count != dynamic_extent); Expects(Count <= size()); return {data(), Count}; } @@ -505,20 +503,19 @@ public: template // clang-format off GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute - // clang-format on - constexpr span last() const noexcept + // clang-format on + constexpr span last() const noexcept { - Expects(Count != dynamic_extent); - Expects(size() >= Count); + Expects(Count <= size()); return {data() + (size() - Count), Count}; } 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 + // clang-format on + constexpr auto subspan() const noexcept -> + typename details::calculate_subspan_type::type { Expects((size() >= Offset) && (Count == dynamic_extent || (Count <= size() - Offset))); @@ -589,8 +586,8 @@ public: constexpr iterator end() const noexcept { const auto data = storage_.data(); - const auto size = storage_.size(); - return {data, data + size, data + size}; + const auto endData = data + storage_.size(); + return {data, endData, endData}; } constexpr const_iterator cbegin() const noexcept @@ -602,8 +599,8 @@ public: constexpr const_iterator cend() const noexcept { const auto data = storage_.data(); - const auto size = storage_.size(); - return {data, data + size, data + size}; + const auto endData = data + storage_.size(); + return {data, endData, endData}; } constexpr reverse_iterator rbegin() const noexcept { return reverse_iterator{end()}; } @@ -767,6 +764,7 @@ namespace details template struct calculate_byte_size : std::integral_constant { + static_assert(Extent < dynamic_extent / sizeof(ElementType), "Size is too big."); }; template @@ -843,12 +841,11 @@ 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); + Expects(i >= 0); return s[static_cast(i)]; } diff --git a/tests/span_compatibility_tests.cpp b/tests/span_compatibility_tests.cpp index 57a85e7..0301ace 100644 --- a/tests/span_compatibility_tests.cpp +++ b/tests/span_compatibility_tests.cpp @@ -931,6 +931,8 @@ 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, @@ -1048,16 +1050,16 @@ static_assert(std::is_convertible&, gsl::span>::va static_assert(std::is_convertible&, gsl::span>::value, "std::is_convertible&, gsl::span>"); - - + + #if __cplusplus >= 201703l template -inline constexpr bool AsWritableBytesCompilesFor = false; +static constexpr bool AsWritableBytesCompilesFor = false; template -inline constexpr bool AsWritableBytesCompilesFor()))>> = +static constexpr bool AsWritableBytesCompilesFor()))>> = true; - + static_assert(AsWritableBytesCompilesFor>, "AsWritableBytesCompilesFor>"); static_assert(AsWritableBytesCompilesFor>, From 46603698ec9a37b07c2a39926c47cb465bda0aa8 Mon Sep 17 00:00:00 2001 From: "Jordan Maples [MSFT]" <49793787+JordanMaples@users.noreply.github.com> Date: Tue, 18 Feb 2020 15:36:15 -0800 Subject: [PATCH 45/45] rewrite operators in iterator to take advantage of nrvo --- include/gsl/span | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/gsl/span b/include/gsl/span index e3ea0db..0d8dcb0 100644 --- a/include/gsl/span +++ b/include/gsl/span @@ -199,7 +199,8 @@ namespace details constexpr span_iterator operator+(const difference_type n) const noexcept { span_iterator ret = *this; - return ret += n; + ret += n; + return ret; } friend constexpr span_iterator operator+(const difference_type n, @@ -220,7 +221,8 @@ namespace details constexpr span_iterator operator-(const difference_type n) const noexcept { span_iterator ret = *this; - return ret -= n; + ret -= n; + return ret; } template < @@ -343,8 +345,6 @@ namespace details public: using size_type = std::size_t; - static_assert(Ext != dynamic_extent, "A fixed-size span must not have size == dynamic_extent"); - constexpr extent_type() noexcept = default; template