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 b3e5349..0d8dcb0 100644 --- a/include/gsl/span +++ b/include/gsl/span @@ -25,17 +25,17 @@ #include // for array #include // for ptrdiff_t, size_t, nullptr_t #include // for reverse_iterator, distance, random_access_... -#include #include #include // for enable_if_t, declval, is_convertible, inte... #include -#include // for std::addressof #if defined(_MSC_VER) && !defined(__clang__) #pragma warning(push) // turn off some warnings that are noisy about our Expects statements #pragma warning(disable : 4127) // conditional expression is constant +#pragma warning( \ + disable : 4146) // unary minus operator applied to unsigned type, result still unsigned #pragma warning(disable : 4702) // unreachable code // Turn MSVC /analyze rules that generate too much noise. TODO: fix in the tool. @@ -70,9 +70,9 @@ namespace gsl { // [views.constants], constants -constexpr const std::ptrdiff_t dynamic_extent = -1; +constexpr const std::size_t dynamic_extent = static_cast(-1); -template +template class span; // implementation details @@ -83,7 +83,7 @@ namespace details { }; - template + template struct is_span_oracle> : std::true_type { }; @@ -104,156 +104,189 @@ namespace details }; template - struct is_std_array : public is_std_array_oracle> + struct is_std_array : is_std_array_oracle> { }; - template + template struct is_allowed_extent_conversion - : public std::integral_constant + : std::integral_constant { }; template struct is_allowed_element_type_conversion - : public std::integral_constant::value> + : std::integral_constant::value> { }; - template + template class span_iterator { - using element_type_ = typename Span::element_type; - public: -#ifdef _MSC_VER - // Tell Microsoft standard library that span_iterators are checked. - using _Unchecked_type = typename Span::pointer; -#endif - using iterator_category = std::random_access_iterator_tag; - using value_type = std::remove_cv_t; - using difference_type = typename Span::index_type; + using value_type = std::remove_cv_t; + using difference_type = std::ptrdiff_t; + using pointer = Type*; + using reference = Type&; - using reference = std::conditional_t&; - using pointer = std::add_pointer_t; +#ifdef _MSC_VER + using _Unchecked_type = pointer; +#endif // _MSC_VER + constexpr span_iterator() = default; - span_iterator() = default; - - constexpr span_iterator(const Span* span, difference_type idx) noexcept - : span_(span), index_(idx) + constexpr span_iterator(pointer begin, pointer end, pointer current) + : begin_(begin), end_(end), current_(current) {} - friend span_iterator; - template * = nullptr> - constexpr span_iterator(const span_iterator& other) noexcept - : span_iterator(other.span_, other.index_) - {} - - GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute - constexpr reference operator*() const + constexpr operator span_iterator() const noexcept { - Expects(index_ != span_->size()); - return *(span_->data() + index_); + return {begin_, end_, current_}; } - constexpr pointer operator->() const + constexpr reference operator*() const noexcept { - Expects(index_ != span_->size()); - return span_->data() + index_; + Expects(begin_ && end_); + Expects(begin_ <= current_ && current_ < end_); + return *current_; } + constexpr pointer operator->() const noexcept + { + Expects(begin_ && end_); + Expects(begin_ <= current_ && current_ < end_); + return current_; + } constexpr span_iterator& operator++() noexcept { - Expects(0 <= index_ && index_ != span_->size()); - ++index_; + Expects(begin_ && current_ && end_); + Expects(current_ < end_); + ++current_; return *this; } constexpr span_iterator operator++(int) noexcept { - auto ret = *this; - ++(*this); + span_iterator ret = *this; + ++*this; return ret; } constexpr span_iterator& operator--() noexcept { - Expects(index_ != 0 && index_ <= span_->size()); - --index_; + Expects(begin_ && end_); + Expects(begin_ < current_); + --current_; return *this; } constexpr span_iterator operator--(int) noexcept { - auto ret = *this; - --(*this); + span_iterator ret = *this; + --*this; return ret; } - constexpr span_iterator operator+(difference_type n) const noexcept + constexpr span_iterator& operator+=(const difference_type n) noexcept { - auto ret = *this; - return ret += n; + if (n != 0) Expects(begin_ && current_ && end_); + if (n > 0) Expects(end_ - current_ >= n); + if (n < 0) Expects(current_ - begin_ >= -n); + current_ += n; + return *this; } - friend constexpr span_iterator operator+(difference_type n, span_iterator const& rhs) noexcept + constexpr span_iterator operator+(const difference_type n) const noexcept + { + span_iterator ret = *this; + ret += n; + return ret; + } + + friend constexpr span_iterator operator+(const difference_type n, + const span_iterator& rhs) noexcept { return rhs + n; } - constexpr span_iterator& operator+=(difference_type n) noexcept + constexpr span_iterator& operator-=(const difference_type n) noexcept { - Expects((index_ + n) >= 0 && (index_ + n) <= span_->size()); - index_ += n; + if (n != 0) Expects(begin_ && current_ && end_); + if (n > 0) Expects(current_ - begin_ >= n); + if (n < 0) Expects(end_ - current_ >= -n); + current_ -= n; return *this; } - constexpr span_iterator operator-(difference_type n) const noexcept + constexpr span_iterator operator-(const difference_type n) const noexcept { - auto ret = *this; - return ret -= n; + span_iterator ret = *this; + ret -= n; + return ret; } - constexpr span_iterator& operator-=(difference_type n) noexcept { return *this += -n; } - - constexpr difference_type operator-(span_iterator rhs) const noexcept + template < + class Type2, + std::enable_if_t, value_type>::value, int> = 0> + constexpr difference_type operator-(const span_iterator& rhs) const noexcept { - Expects(span_ == rhs.span_); - return index_ - rhs.index_; + Expects(begin_ == rhs.begin_ && end_ == rhs.end_); + return current_ - rhs.current_; } - constexpr reference operator[](difference_type n) const noexcept { return *(*this + n); } - - constexpr friend bool operator==(span_iterator lhs, span_iterator rhs) noexcept + constexpr reference operator[](const difference_type n) const noexcept { - return lhs.span_ == rhs.span_ && lhs.index_ == rhs.index_; + return *(*this + n); } - constexpr friend bool operator!=(span_iterator lhs, span_iterator rhs) noexcept + template < + class Type2, + std::enable_if_t, value_type>::value, int> = 0> + constexpr bool operator==(const span_iterator& rhs) const noexcept { - return !(lhs == rhs); + Expects(begin_ == rhs.begin_ && end_ == rhs.end_); + return current_ == rhs.current_; } - constexpr friend bool operator<(span_iterator lhs, span_iterator rhs) noexcept + template < + class Type2, + std::enable_if_t, value_type>::value, int> = 0> + constexpr bool operator!=(const span_iterator& rhs) const noexcept { - return lhs.index_ < rhs.index_; + return !(*this == rhs); } - constexpr friend bool operator<=(span_iterator lhs, span_iterator rhs) noexcept + template < + class Type2, + std::enable_if_t, value_type>::value, int> = 0> + constexpr bool operator<(const span_iterator& rhs) const noexcept { - return !(rhs < lhs); + Expects(begin_ == rhs.begin_ && end_ == rhs.end_); + return current_ < rhs.current_; } - constexpr friend bool operator>(span_iterator lhs, span_iterator rhs) noexcept + template < + class Type2, + std::enable_if_t, value_type>::value, int> = 0> + constexpr bool operator>(const span_iterator& rhs) const noexcept { - return rhs < lhs; + return rhs < *this; } - constexpr friend bool operator>=(span_iterator lhs, span_iterator rhs) noexcept + template < + class Type2, + std::enable_if_t, value_type>::value, int> = 0> + constexpr bool operator<=(const span_iterator& rhs) const noexcept { - return !(rhs > lhs); + return !(rhs < *this); + } + + template < + class Type2, + std::enable_if_t, value_type>::value, int> = 0> + constexpr bool operator>=(const span_iterator& rhs) const noexcept + { + return !(*this < rhs); } #ifdef _MSC_VER @@ -262,22 +295,26 @@ namespace details // algorithm calls friend constexpr void _Verify_range(span_iterator lhs, span_iterator rhs) noexcept { // test that [lhs, rhs) forms a valid range inside an STL algorithm - Expects(lhs.span_ == rhs.span_ // range spans have to match - && lhs.index_ <= rhs.index_); // range must not be transposed + Expects(lhs.begin_ == rhs.begin_ // range spans have to match + && lhs.end_ == rhs.end_ && + lhs.current_ <= rhs.current_); // range must not be transposed } constexpr void _Verify_offset(const difference_type n) const noexcept - { // test that the iterator *this + n is a valid range in an STL - // algorithm call - Expects((index_ + n) >= 0 && (index_ + n) <= span_->size()); + { // test that *this + n is within the range of this call + if (n != 0) Expects(begin_ && current_ && end_); + if (n > 0) Expects(end_ - current_ >= n); + if (n < 0) Expects(current_ - begin_ >= -n); } + // clang-format off GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute + // clang-format on constexpr pointer _Unwrapped() const noexcept { // after seeking *this to a high water mark, or using one of the // _Verify_xxx functions above, unwrap this span_iterator to a raw // pointer - return span_->data() + index_; + return current_; } // Tell the STL that span_iterator should not be unwrapped if it can't @@ -287,61 +324,64 @@ namespace details #else static constexpr bool _Unwrap_when_unverified = false; #endif + // clang-format off GSL_SUPPRESS(con.3) // NO-FORMAT: attribute // TODO: false positive + // clang-format on constexpr void _Seek_to(const pointer p) noexcept { // adjust the position of *this to previously verified location p // after _Unwrapped - index_ = p - span_->data(); + current_ = p; } #endif - protected: - const Span* span_ = nullptr; - std::ptrdiff_t index_ = 0; + pointer begin_ = nullptr; + pointer end_ = nullptr; + pointer current_ = nullptr; }; - template + template class extent_type { public: - using index_type = std::ptrdiff_t; + using size_type = std::size_t; - static_assert(Ext >= 0, "A fixed-size span must be >= 0 in size."); + constexpr extent_type() noexcept = default; - constexpr extent_type() noexcept {} - - template + template constexpr extent_type(extent_type ext) { - static_assert(Other == Ext || Other == dynamic_extent, + static_assert(Other == Ext, "Mismatch between fixed-size extent and size of initializing data."); Expects(ext.size() == Ext); } - constexpr extent_type(index_type size) { Expects(size == Ext); } + constexpr extent_type(size_type size) { Expects(size == Ext); } - constexpr index_type size() const noexcept { return Ext; } + constexpr size_type size() const noexcept { return Ext; } }; template <> class extent_type { public: - using index_type = std::ptrdiff_t; + using size_type = std::size_t; - template + template explicit constexpr extent_type(extent_type ext) : size_(ext.size()) {} - explicit constexpr extent_type(index_type size) : size_(size) { Expects(size >= 0); } + explicit constexpr extent_type(size_type size) : size_(size) + { + Expects(size != dynamic_extent); + } - constexpr index_type size() const noexcept { return size_; } + constexpr size_type size() const noexcept { return size_; } private: - index_type size_; + size_type size_; }; - template + template struct calculate_subspan_type { using type = span +template class span { public: // constants and types using element_type = ElementType; using value_type = std::remove_cv_t; - using index_type = std::ptrdiff_t; + using size_type = std::size_t; using pointer = element_type*; + using const_pointer = const element_type*; using reference = element_type&; + using const_reference = const element_type&; + using difference_type = std::ptrdiff_t; - using iterator = details::span_iterator, false>; - using const_iterator = details::span_iterator, true>; + using iterator = details::span_iterator; + using const_iterator = details::span_iterator; using reverse_iterator = std::reverse_iterator; using const_reverse_iterator = std::reverse_iterator; - using size_type = index_type; - #if defined(GSL_USE_STATIC_CONSTEXPR_WORKAROUND) - static constexpr const index_type extent{Extent}; + static constexpr const size_type extent{Extent}; #else - static constexpr index_type extent{Extent}; + static constexpr size_type extent{Extent}; #endif // [span.cons], span constructors, copy, assignment, and destructor template " SFINAE, - // since "std::enable_if_t" is ill-formed when Extent is greater than 0. - class = std::enable_if_t<(Dependent || Extent <= 0)>> + // "Dependent" is needed to make "std::enable_if_t" SFINAE, since "std::enable_if_t" is ill-formed when Extent is greater than 0. + class = std::enable_if_t<(Dependent || + details::is_allowed_extent_conversion<0, Extent>::value)>> constexpr span() noexcept : storage_(nullptr, details::extent_type<0>()) {} - constexpr span(pointer ptr, index_type count) noexcept: storage_(ptr, count) {} + constexpr span(pointer ptr, size_type count) noexcept : storage_(ptr, count) + { + if (Extent != dynamic_extent) Expects(count == Extent); + } constexpr span(pointer firstElem, pointer lastElem) noexcept - : storage_(firstElem, std::distance(firstElem, lastElem)) - {} + : storage_(firstElem, static_cast(lastElem - firstElem)) + { + if (Extent != dynamic_extent) + { Expects(lastElem - firstElem == static_cast(Extent)); } + } - template + template ::value, int> = 0> constexpr span(element_type (&arr)[N]) noexcept - : storage_(KnownNotNull{std::addressof(arr[0])}, details::extent_type()) + : storage_(KnownNotNull{arr + 0}, details::extent_type()) {} - template 0)>> - constexpr span(std::array, N>& arr) noexcept + template ::value, int> = 0> + constexpr span(std::array& arr) noexcept : storage_(KnownNotNull{arr.data()}, details::extent_type()) - { - } + {} - constexpr span(std::array, 0>&) noexcept - : storage_(static_cast(nullptr), details::extent_type<0>()) - { - } - - template 0)>> - constexpr span(const std::array, N>& arr) noexcept + template ::value && + details::is_allowed_element_type_conversion::value), + int> = 0> + constexpr span(const std::array& arr) noexcept : storage_(KnownNotNull{arr.data()}, details::extent_type()) - { - } + {} - constexpr span(const std::array, 0>&) noexcept - : storage_(static_cast(nullptr), details::extent_type<0>()) - { - } - - // NB: the SFINAE here uses .data() as a incomplete/imperfect proxy for the requirement + // NB: the SFINAE here uses .data() as an incomplete/imperfect proxy for the requirement // on Container to be a contiguous sequence container. template ::value && !details::is_std_array::value && - std::is_convertible::value && - std::is_convertible().data())>::value>> - constexpr span(Container& cont) noexcept : span(cont.data(), narrow(cont.size())) + std::is_pointer().data())>::value && + std::is_convertible().data())>(*)[], element_type(*)[]>::value>> + constexpr span(Container& cont) noexcept : span(cont.data(), cont.size()) {} template ::value && !details::is_span::value && - std::is_convertible::value && - std::is_convertible().data())>::value>> - constexpr span(const Container& cont) noexcept : span(cont.data(), narrow(cont.size())) + !details::is_std_array::value && + std::is_pointer().data())>::value && + std::is_convertible().data())>(*)[], element_type(*)[]>::value>> + constexpr span(const Container& cont) noexcept : span(cont.data(), cont.size()) {} constexpr span(const span& other) noexcept = default; template < - class OtherElementType, std::ptrdiff_t OtherExtent, + class OtherElementType, std::size_t OtherExtent, class = std::enable_if_t< details::is_allowed_extent_conversion::value && details::is_allowed_element_type_conversion::value>> @@ -451,62 +493,72 @@ public: constexpr span& operator=(const span& other) noexcept = default; // [span.sub], span subviews - template + template constexpr span first() const noexcept { - Expects(Count >= 0 && Count <= size()); + Expects(Count <= size()); return {data(), Count}; } - template + template + // clang-format off GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute + // clang-format on constexpr span last() const noexcept { - Expects(Count >= 0 && size() - Count >= 0); + Expects(Count <= size()); return {data() + (size() - Count), Count}; } - template + template + // clang-format off GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute + // clang-format on constexpr auto subspan() const noexcept -> - typename details::calculate_subspan_type::type + typename details::calculate_subspan_type::type { - Expects((Offset >= 0 && size() - Offset >= 0) && - (Count == dynamic_extent || (Count >= 0 && Offset + Count <= size()))); + Expects((size() >= Offset) && (Count == dynamic_extent || (Count <= size() - Offset))); return {data() + Offset, Count == dynamic_extent ? size() - Offset : Count}; } - constexpr span first(index_type count) const noexcept + constexpr span first(size_type count) const noexcept { - Expects(count >= 0 && count <= size()); + Expects(count <= size()); return {data(), count}; } - constexpr span last(index_type count) const noexcept + constexpr span last(size_type count) const noexcept { + Expects(count <= size()); return make_subspan(size() - count, dynamic_extent, subspan_selector{}); } - constexpr span subspan(index_type offset, - index_type count = dynamic_extent) const noexcept + constexpr span subspan(size_type offset, + size_type count = dynamic_extent) const + noexcept { return make_subspan(offset, count, subspan_selector{}); } // [span.obs], span observers - constexpr index_type size() const noexcept { return storage_.size(); } - constexpr index_type size_bytes() const noexcept + constexpr size_type size() const noexcept { return storage_.size(); } + + constexpr size_type size_bytes() const noexcept { - return size() * narrow_cast(sizeof(element_type)); + Expects(size() < dynamic_extent / sizeof(element_type)); + return size() * sizeof(element_type); } + constexpr bool empty() const noexcept { return size() == 0; } // [span.elem], span element access + // clang-format off GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute - constexpr reference operator[](index_type idx) const noexcept + // clang-format on + constexpr reference operator[](size_type idx) const noexcept { - Expects(CheckRange(idx, storage_.size())); + Expects(idx < size()); return data()[idx]; } @@ -521,23 +573,35 @@ public: Expects(size() > 0); return data()[size() - 1]; } - - // at and operator() are deprecated to align to the public member functions of std::span - [[deprecated("Use operator[]")]] - constexpr reference at(index_type idx) const noexcept{ return this->operator[](idx); } - [[deprecated("Use operator[]")]] - constexpr reference operator()(index_type idx) const noexcept{ return this->operator[](idx); } - - constexpr pointer data() const noexcept { return storage_.data(); } // [span.iter], span iterator support - constexpr iterator begin() const noexcept { return {this, 0}; } - constexpr iterator end() const noexcept { return {this, size()}; } + constexpr iterator begin() const noexcept + { + const auto data = storage_.data(); + return {data, data + size(), data}; + } - constexpr const_iterator cbegin() const noexcept { return {this, 0}; } - constexpr const_iterator cend() const noexcept { return {this, size()}; } + constexpr iterator end() const noexcept + { + const auto data = storage_.data(); + const auto endData = data + storage_.size(); + return {data, endData, endData}; + } + + constexpr const_iterator cbegin() const noexcept + { + const auto data = storage_.data(); + return {data, data + size(), data}; + } + + constexpr const_iterator cend() const noexcept + { + const auto data = storage_.data(); + const auto endData = data + storage_.size(); + return {data, endData, endData}; + } constexpr reverse_iterator rbegin() const noexcept { return reverse_iterator{end()}; } constexpr reverse_iterator rend() const noexcept { return reverse_iterator{begin()}; } @@ -556,38 +620,14 @@ public: constexpr pointer _Unchecked_begin() const noexcept { return data(); } constexpr pointer _Unchecked_end() const noexcept { + // clang-format off GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute + // clang-format on return data() + size(); } #endif // _MSC_VER private: - static constexpr bool CheckRange(index_type idx, index_type size) noexcept - { - // Optimization: - // - // idx >= 0 && idx < size - // => - // static_cast(idx) < static_cast(size) - // - // because size >=0 by span construction, and negative idx will - // wrap around to a value always greater than size when casted. - - // check if we have enough space to wrap around -#if defined(__cpp_if_constexpr) - if constexpr (sizeof(index_type) <= sizeof(size_t)) -#else - if (sizeof(index_type) <= sizeof(size_t)) -#endif - { - return narrow_cast(idx) < narrow_cast(size); - } - else - { - return idx >= 0 && idx < size; - } - } - // Needed to remove unnecessary null check in subspans struct KnownNotNull { @@ -607,13 +647,13 @@ private: constexpr storage_type(KnownNotNull data, OtherExtentType ext) : ExtentType(ext), data_(data.p) { - Expects(ExtentType::size() >= 0); + Expects(ExtentType::size() != dynamic_extent); } template constexpr storage_type(pointer data, OtherExtentType ext) : ExtentType(ext), data_(data) { - Expects(ExtentType::size() >= 0); + Expects(ExtentType::size() != dynamic_extent); Expects(data || ExtentType::size() == 0); } @@ -627,71 +667,87 @@ private: // The rest is needed to remove unnecessary null check // in subspans and constructors from arrays - constexpr span(KnownNotNull ptr, index_type count) : storage_(ptr, count) {} + constexpr span(KnownNotNull ptr, size_type count) noexcept : storage_(ptr, count) {} - template + template class subspan_selector { }; - template - span make_subspan(index_type offset, index_type count, - subspan_selector) const + template + constexpr span make_subspan(size_type offset, size_type count, + subspan_selector) const noexcept { const span tmp(*this); return tmp.subspan(offset, count); } + // clang-format off GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute - span make_subspan(index_type offset, index_type count, - subspan_selector) const + // clang-format on + constexpr span + make_subspan(size_type offset, size_type count, subspan_selector) const noexcept { - Expects(offset >= 0 && size() - offset >= 0); + Expects(size() >= offset); if (count == dynamic_extent) { return {KnownNotNull{data() + offset}, size() - offset}; } - Expects(count >= 0 && size() - offset >= count); + Expects(size() - offset >= count); return {KnownNotNull{data() + offset}, count}; } }; +#if (defined(__cpp_deduction_guides) && (__cpp_deduction_guides >= 201611L)) + +// Deduction Guides +template +span(Type (&)[Extent])->span; + +template +span(std::array&)->span; + +template +span(const std::array&)->span; + +#endif // ( defined(__cpp_deduction_guides) && (__cpp_deduction_guides >= 201611L) ) + #if defined(GSL_USE_STATIC_CONSTEXPR_WORKAROUND) -template -constexpr const typename span::index_type span::extent; +template +constexpr const typename span::size_type span::extent; #endif // [span.comparison], span comparison operators -template +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 +761,38 @@ namespace details // we should use a narrow_cast<> to go to std::size_t, but older compilers may not see it as // constexpr // and so will fail compilation of the template - template - struct calculate_byte_size - : std::integral_constant(sizeof(ElementType) * - static_cast(Extent))> + template + struct calculate_byte_size : std::integral_constant { + static_assert(Extent < dynamic_extent / sizeof(ElementType), "Size is too big."); }; template struct calculate_byte_size - : std::integral_constant + : std::integral_constant { }; } // namespace details // [span.objectrep], views of object representation -template +template span::value> as_bytes(span s) noexcept { + // clang-format off GSL_SUPPRESS(type.1) // NO-FORMAT: attribute + // clang-format on return {reinterpret_cast(s.data()), s.size_bytes()}; } -template ::value>> +template ::value, int> = 0> span::value> -as_writeable_bytes(span s) noexcept +as_writable_bytes(span s) noexcept { + // clang-format off GSL_SUPPRESS(type.1) // NO-FORMAT: attribute + // clang-format on return {reinterpret_cast(s.data()), s.size_bytes()}; } @@ -742,8 +800,7 @@ as_writeable_bytes(span s) noexcept // make_span() - Utility functions for creating spans // template -constexpr span make_span(ElementType* ptr, - typename span::index_type count) +constexpr span make_span(ElementType* ptr, typename span::size_type count) { return span(ptr, count); } @@ -773,7 +830,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); } @@ -784,68 +841,76 @@ constexpr span make_span(Ptr& cont) return span(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 - return s[i]; + Expects(i >= 0); + return s[static_cast(i)]; } // [span.obs] Free observer functions -template -constexpr typename span::index_type ssize(const span &span) noexcept +template +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 +template +constexpr typename span::iterator +begin(const span& s) noexcept { - return span.begin(); + return s.begin(); } -template -constexpr typename span::iterator end(const span &span) noexcept +template +constexpr typename span::iterator +end(const span& s) noexcept { - return span.end(); + return s.end(); } -template -constexpr typename span::const_iterator cbegin(const span &span) noexcept +template +constexpr typename span::const_iterator +cbegin(const span& s) noexcept { - return span.cbegin(); + return s.cbegin(); } -template -constexpr typename span::const_iterator cend(const span &span) noexcept +template +constexpr typename span::const_iterator +cend(const span& s) noexcept { - return span.cend(); + return s.cend(); } -template -constexpr typename span::reverse_iterator rbegin(const span &span) noexcept +template +constexpr typename span::reverse_iterator +rbegin(const span& s) noexcept { - return span.rbegin(); + return s.rbegin(); } -template -constexpr typename span::reverse_iterator rend(const span &span) noexcept +template +constexpr typename span::reverse_iterator +rend(const span& s) noexcept { - return span.rend(); + return s.rend(); } -template -constexpr typename span::const_reverse_iterator crbegin(const span &span) noexcept +template +constexpr typename span::const_reverse_iterator +crbegin(const span& s) noexcept { - return span.crbegin(); + return s.crbegin(); } -template -constexpr typename span::const_reverse_iterator crend(const span &span) noexcept +template +constexpr typename span::const_reverse_iterator +crend(const span& s) noexcept { - return span.crend(); + return s.crend(); } } // namespace gsl diff --git a/include/gsl/string_span b/include/gsl/string_span index 37cbe15..cc0588e 100644 --- a/include/gsl/string_span +++ b/include/gsl/string_span @@ -23,10 +23,10 @@ #include // for equal, lexicographical_compare #include // for array -#include // for ptrdiff_t, size_t, nullptr_t +#include // for size_t, nullptr_t #include // for PTRDIFF_MAX #include -#include // for basic_string, allocator, char_traits +#include // for basic_string, allocator, char_traits #include // for declval, is_convertible, enable_if_t, add_... #if defined(_MSC_VER) && !defined(__clang__) @@ -56,43 +56,43 @@ namespace gsl // (sometimes needlessly) break existing programs when introduced. // -template +template using basic_zstring = CharT*; -template +template using czstring = basic_zstring; -template +template using cwzstring = basic_zstring; -template +template using cu16zstring = basic_zstring; -template +template using cu32zstring = basic_zstring; -template +template using zstring = basic_zstring; -template +template using wzstring = basic_zstring; -template +template using u16zstring = basic_zstring; -template +template using u32zstring = basic_zstring; namespace details { template - std::ptrdiff_t string_length(const CharT* str, std::ptrdiff_t n) + std::size_t string_length(const CharT* str, std::size_t n) { - if (str == nullptr || n <= 0) return 0; + if (str == nullptr || n == dynamic_extent) return 0; const span str_span{str, n}; - std::ptrdiff_t len = 0; + std::size_t len = 0; while (len < n && str_span[len]) len++; return len; @@ -108,18 +108,20 @@ namespace details // Will fail-fast if sentinel cannot be found before max elements are examined. // template -span ensure_sentinel(T* seq, std::ptrdiff_t max = PTRDIFF_MAX) +span ensure_sentinel(T* seq, + std::size_t max = static_cast(-1)) { Ensures(seq != nullptr); - GSL_SUPPRESS(f.23) // NO-FORMAT: attribute // TODO: false positive // TODO: suppress does not work + GSL_SUPPRESS( + f.23) // NO-FORMAT: attribute // TODO: false positive // TODO: suppress does not work auto cur = seq; Ensures(cur != nullptr); // workaround for removing the warning GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute // TODO: suppress does not work - while ((cur - seq) < max && *cur != Sentinel) ++cur; + while (static_cast(cur - seq) < max && *cur != Sentinel) ++cur; Ensures(*cur == Sentinel); - return {seq, cur - seq}; + return {seq, static_cast(cur - seq)}; } // @@ -128,7 +130,8 @@ span ensure_sentinel(T* seq, std::ptrdiff_t max = PTRDIFF_MAX // the limit of size_type. // template -span ensure_z(CharT* const& sz, std::ptrdiff_t max = PTRDIFF_MAX) +span ensure_z(CharT* const& sz, + std::size_t max = static_cast(-1)) { return ensure_sentinel(sz, max); } @@ -136,26 +139,27 @@ span ensure_z(CharT* const& sz, std::ptrdiff_t max = PTRD template span ensure_z(CharT (&sz)[N]) { - return ensure_z(&sz[0], narrow_cast(N)); + return ensure_z(&sz[0], N); } template span::type, dynamic_extent> ensure_z(Cont& cont) { - return ensure_z(cont.data(), narrow_cast(cont.size())); + return ensure_z(cont.data(), cont.size()); } -template +template class basic_string_span; -namespace details { +namespace details +{ template struct is_basic_string_span_oracle : std::false_type { }; - template + template struct is_basic_string_span_oracle> : std::true_type { }; @@ -169,7 +173,7 @@ namespace details { // // string_span and relatives // -template +template class basic_string_span { public: @@ -180,14 +184,12 @@ public: using const_reference = std::add_lvalue_reference_t>; using impl_type = span; - using index_type = typename impl_type::index_type; + using size_type = typename impl_type::size_type; using iterator = typename impl_type::iterator; using const_iterator = typename impl_type::const_iterator; using reverse_iterator = typename impl_type::reverse_iterator; using const_reverse_iterator = typename impl_type::const_reverse_iterator; - using size_type = index_type; - // default (empty) constexpr basic_string_span() noexcept = default; @@ -197,7 +199,7 @@ public: // assign constexpr basic_string_span& operator=(const basic_string_span& other) noexcept = default; - constexpr basic_string_span(pointer ptr, index_type length) : span_(ptr, length) {} + constexpr basic_string_span(pointer ptr, size_type length) : span_(ptr, length) {} constexpr basic_string_span(pointer firstElem, pointer lastElem) : span_(firstElem, lastElem) {} // From static arrays - if 0-terminated, remove 0 from the view @@ -218,7 +220,7 @@ public: template // GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute // TODO: parser bug constexpr basic_string_span(std::basic_string& str) - : span_(&str[0], narrow_cast(str.length())) + : span_(&str[0], str.length()) {} template @@ -247,56 +249,56 @@ public: // from string_span template < - class OtherValueType, std::ptrdiff_t OtherExtent, + class OtherValueType, std::size_t OtherExtent, class = std::enable_if_t::impl_type, impl_type>::value>> constexpr basic_string_span(basic_string_span other) : span_(other.data(), other.length()) {} - template + template constexpr basic_string_span first() const { return {span_.template first()}; } - constexpr basic_string_span first(index_type count) const + constexpr basic_string_span first(size_type count) const { return {span_.first(count)}; } - template + template constexpr basic_string_span last() const { return {span_.template last()}; } - constexpr basic_string_span last(index_type count) const + constexpr basic_string_span last(size_type count) const { return {span_.last(count)}; } - template + template constexpr basic_string_span subspan() const { return {span_.template subspan()}; } constexpr basic_string_span - subspan(index_type offset, index_type count = dynamic_extent) const + subspan(size_type offset, size_type count = dynamic_extent) const { return {span_.subspan(offset, count)}; } - constexpr reference operator[](index_type idx) const { return span_[idx]; } - constexpr reference operator()(index_type idx) const { return span_[idx]; } + constexpr reference operator[](size_type idx) const { return span_[idx]; } + constexpr reference operator()(size_type idx) const { return span_[idx]; } constexpr pointer data() const { return span_.data(); } - constexpr index_type length() const noexcept { return span_.size(); } - constexpr index_type size() const noexcept { return span_.size(); } - constexpr index_type size_bytes() const noexcept { return span_.size_bytes(); } - constexpr index_type length_bytes() const noexcept { return span_.length_bytes(); } + constexpr size_type length() const noexcept { return span_.size(); } + constexpr size_type size() const noexcept { return span_.size(); } + constexpr size_type size_bytes() const noexcept { return span_.size_bytes(); } + constexpr size_type length_bytes() const noexcept { return span_.length_bytes(); } constexpr bool empty() const noexcept { return size() == 0; } constexpr iterator begin() const noexcept { return span_.begin(); } @@ -312,7 +314,7 @@ public: constexpr const_reverse_iterator crend() const noexcept { return span_.crend(); } private: - static impl_type remove_z(pointer const& sz, std::ptrdiff_t max) + static impl_type remove_z(pointer const& sz, std::size_t max) { return {sz, details::string_length(sz, max)}; } @@ -320,41 +322,41 @@ private: template static impl_type remove_z(element_type (&sz)[N]) { - return remove_z(&sz[0], narrow_cast(N)); + return remove_z(&sz[0], N); } impl_type span_; }; -template +template using string_span = basic_string_span; -template +template using cstring_span = basic_string_span; -template +template using wstring_span = basic_string_span; -template +template using cwstring_span = basic_string_span; -template +template using u16string_span = basic_string_span; -template +template using cu16string_span = basic_string_span; -template +template using u32string_span = basic_string_span; -template +template using cu32string_span = basic_string_span; // // to_string() allow (explicit) conversions from string_span to string // -template +template std::basic_string::type> to_string(basic_string_span view) { @@ -362,13 +364,13 @@ to_string(basic_string_span view) } template , - typename Allocator = std::allocator, typename gCharT, std::ptrdiff_t Extent> + typename Allocator = std::allocator, typename gCharT, std::size_t Extent> std::basic_string to_basic_string(basic_string_span view) { return {view.data(), narrow_cast(view.length())}; } -template +template basic_string_span::value> as_bytes(basic_string_span s) noexcept { @@ -376,10 +378,10 @@ as_bytes(basic_string_span s) noexcept return {reinterpret_cast(s.data()), s.size_bytes()}; } -template ::value>> basic_string_span::value> -as_writeable_bytes(basic_string_span s) noexcept +as_writable_bytes(basic_string_span s) noexcept { GSL_SUPPRESS(type.1) // NO-FORMAT: attribute return {reinterpret_cast(s.data()), s.size_bytes()}; @@ -387,8 +389,9 @@ as_writeable_bytes(basic_string_span s) noexcept // zero-terminated string span, used to convert // zero-terminated spans to legacy strings -template -class basic_zstring_span { +template +class basic_zstring_span +{ public: using value_type = CharT; using const_value_type = std::add_const_t; @@ -435,32 +438,32 @@ private: impl_type span_; }; -template +template using zstring_span = basic_zstring_span; -template +template using wzstring_span = basic_zstring_span; -template +template using u16zstring_span = basic_zstring_span; -template +template using u32zstring_span = basic_zstring_span; -template +template using czstring_span = basic_zstring_span; -template +template using cwzstring_span = basic_zstring_span; -template +template using cu16zstring_span = basic_zstring_span; -template +template using cu32zstring_span = basic_zstring_span; // operator == -template ::value || std::is_convertible>>::value>> @@ -470,7 +473,7 @@ bool operator==(const gsl::basic_string_span& one, const T& other return std::equal(one.begin(), one.end(), tmp.begin(), tmp.end()); } -template ::value && std::is_convertible>>::value>> @@ -481,7 +484,7 @@ bool operator==(const T& one, const gsl::basic_string_span& other } // operator != -template , Extent>>::value>> bool operator!=(gsl::basic_string_span one, const T& other) @@ -490,7 +493,7 @@ bool operator!=(gsl::basic_string_span one, const T& other) } template < - typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T, + typename CharT, std::size_t Extent = gsl::dynamic_extent, typename T, typename = std::enable_if_t< std::is_convertible, Extent>>::value && !gsl::details::is_basic_string_span::value>> @@ -500,7 +503,7 @@ bool operator!=(const T& one, gsl::basic_string_span other) } // operator< -template , Extent>>::value>> bool operator<(gsl::basic_string_span one, const T& other) @@ -510,7 +513,7 @@ bool operator<(gsl::basic_string_span one, const T& other) } template < - typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T, + typename CharT, std::size_t Extent = gsl::dynamic_extent, typename T, typename = std::enable_if_t< std::is_convertible, Extent>>::value && !gsl::details::is_basic_string_span::value>> @@ -526,7 +529,7 @@ bool operator<(const T& one, gsl::basic_string_span other) // so the cases below are already covered by the previous operators template < - typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T, + typename CharT, std::size_t Extent = gsl::dynamic_extent, typename T, typename DataType = typename T::value_type, typename = std::enable_if_t< !gsl::details::is_span::value && !gsl::details::is_basic_string_span::value && @@ -540,7 +543,7 @@ bool operator<(gsl::basic_string_span one, const T& other) } template < - typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T, + typename CharT, std::size_t Extent = gsl::dynamic_extent, typename T, typename DataType = typename T::value_type, typename = std::enable_if_t< !gsl::details::is_span::value && !gsl::details::is_basic_string_span::value && @@ -555,7 +558,7 @@ bool operator<(const T& one, gsl::basic_string_span other) #endif // operator <= -template , Extent>>::value>> bool operator<=(gsl::basic_string_span one, const T& other) @@ -564,7 +567,7 @@ bool operator<=(gsl::basic_string_span one, const T& other) } template < - typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T, + typename CharT, std::size_t Extent = gsl::dynamic_extent, typename T, typename = std::enable_if_t< std::is_convertible, Extent>>::value && !gsl::details::is_basic_string_span::value>> @@ -579,7 +582,7 @@ bool operator<=(const T& one, gsl::basic_string_span other) // so the cases below are already covered by the previous operators template < - typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T, + typename CharT, std::size_t Extent = gsl::dynamic_extent, typename T, typename DataType = typename T::value_type, typename = std::enable_if_t< !gsl::details::is_span::value && !gsl::details::is_basic_string_span::value && @@ -592,7 +595,7 @@ bool operator<=(gsl::basic_string_span one, const T& other) } template < - typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T, + typename CharT, std::size_t Extent = gsl::dynamic_extent, typename T, typename DataType = typename T::value_type, typename = std::enable_if_t< !gsl::details::is_span::value && !gsl::details::is_basic_string_span::value && @@ -606,7 +609,7 @@ bool operator<=(const T& one, gsl::basic_string_span other) #endif // operator> -template , Extent>>::value>> bool operator>(gsl::basic_string_span one, const T& other) @@ -615,7 +618,7 @@ bool operator>(gsl::basic_string_span one, const T& other) } template < - typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T, + typename CharT, std::size_t Extent = gsl::dynamic_extent, typename T, typename = std::enable_if_t< std::is_convertible, Extent>>::value && !gsl::details::is_basic_string_span::value>> @@ -630,7 +633,7 @@ bool operator>(const T& one, gsl::basic_string_span other) // so the cases below are already covered by the previous operators template < - typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T, + typename CharT, std::size_t Extent = gsl::dynamic_extent, typename T, typename DataType = typename T::value_type, typename = std::enable_if_t< !gsl::details::is_span::value && !gsl::details::is_basic_string_span::value && @@ -643,7 +646,7 @@ bool operator>(gsl::basic_string_span one, const T& other) } template < - typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T, + typename CharT, std::size_t Extent = gsl::dynamic_extent, typename T, typename DataType = typename T::value_type, typename = std::enable_if_t< !gsl::details::is_span::value && !gsl::details::is_basic_string_span::value && @@ -657,7 +660,7 @@ bool operator>(const T& one, gsl::basic_string_span other) #endif // operator >= -template , Extent>>::value>> bool operator>=(gsl::basic_string_span one, const T& other) @@ -666,7 +669,7 @@ bool operator>=(gsl::basic_string_span one, const T& other) } template < - typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T, + typename CharT, std::size_t Extent = gsl::dynamic_extent, typename T, typename = std::enable_if_t< std::is_convertible, Extent>>::value && !gsl::details::is_basic_string_span::value>> @@ -681,7 +684,7 @@ bool operator>=(const T& one, gsl::basic_string_span other) // so the cases below are already covered by the previous operators template < - typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T, + typename CharT, std::size_t Extent = gsl::dynamic_extent, typename T, typename DataType = typename T::value_type, typename = std::enable_if_t< !gsl::details::is_span::value && !gsl::details::is_basic_string_span::value && @@ -694,7 +697,7 @@ bool operator>=(gsl::basic_string_span one, const T& other) } template < - typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T, + typename CharT, std::size_t Extent = gsl::dynamic_extent, typename T, typename DataType = typename T::value_type, typename = std::enable_if_t< !gsl::details::is_span::value && !gsl::details::is_basic_string_span::value && diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 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/CMakeLists.txt.in b/tests/CMakeLists.txt.in index 50c041d..f380b8f 100644 --- a/tests/CMakeLists.txt.in +++ b/tests/CMakeLists.txt.in @@ -4,7 +4,7 @@ project(googletest-download NONE) include(ExternalProject) ExternalProject_Add(googletest GIT_REPOSITORY https://github.com/google/googletest.git - GIT_TAG master + GIT_TAG 703bd9caab50b139428cea1aaff9974ebee5742e SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-src" BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-build" CONFIGURE_COMMAND "" diff --git a/tests/span_compatibility_tests.cpp b/tests/span_compatibility_tests.cpp new file mode 100644 index 0000000..0301ace --- /dev/null +++ b/tests/span_compatibility_tests.cpp @@ -0,0 +1,1071 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// 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"); + +TEST(span_compatibility_tests, assertion_tests) +{ + int arr[3]{10, 20, 30}; + std::array stl{{100, 200, 300}}; + + { + gsl::span sp_dyn; + EXPECT_TRUE(sp_dyn.data() == nullptr); + EXPECT_TRUE(sp_dyn.size() == 0); + EXPECT_TRUE(sp_dyn.empty()); + } + { + gsl::span sp_zero; + EXPECT_TRUE(sp_zero.data() == nullptr); + EXPECT_TRUE(sp_zero.size() == 0); + EXPECT_TRUE(sp_zero.empty()); + + gsl::span sp_dyn_a(arr, 3); + gsl::span sp_dyn_b(begin(arr), 3); + EXPECT_TRUE(sp_dyn_a.data() == std::begin(arr)); + EXPECT_TRUE(sp_dyn_b.data() == std::begin(arr)); + EXPECT_TRUE(sp_dyn_a.size() == 3); + EXPECT_TRUE(sp_dyn_b.size() == 3); + + gsl::span sp_three_a(arr, 3); + gsl::span sp_three_b(begin(arr), 3); + EXPECT_TRUE(sp_three_a.data() == std::begin(arr)); + EXPECT_TRUE(sp_three_b.data() == std::begin(arr)); + EXPECT_TRUE(sp_three_a.size() == 3); + EXPECT_TRUE(sp_three_b.size() == 3); + + gsl::span sp_const_a(arr, 3); + gsl::span sp_const_b(begin(arr), 3); + EXPECT_TRUE(sp_const_a.data() == std::begin(arr)); + EXPECT_TRUE(sp_const_b.data() == std::begin(arr)); + EXPECT_TRUE(sp_const_a.size() == 3); + EXPECT_TRUE(sp_const_b.size() == 3); + +#if __cplusplus >= 201703l + gsl::span sp_const_c(std::as_const(arr), 3); + EXPECT_TRUE(sp_const_c.data() == std::begin(arr)); + EXPECT_TRUE(sp_const_c.size() == 3); +#endif // __cplusplus >= 201703l + + gsl::span sp_const_d(cbegin(arr), 3); + EXPECT_TRUE(sp_const_d.data() == std::begin(arr)); + EXPECT_TRUE(sp_const_d.size() == 3); + } + { + gsl::span sp_dyn_a(begin(arr), std::end(arr)); + EXPECT_TRUE(sp_dyn_a.data() == std::begin(arr)); + EXPECT_TRUE(sp_dyn_a.size() == 3); + + gsl::span sp_three_a(begin(arr), std::end(arr)); + EXPECT_TRUE(sp_three_a.data() == std::begin(arr)); + EXPECT_TRUE(sp_three_a.size() == 3); + + gsl::span sp_const_a(begin(arr), std::end(arr)); + gsl::span sp_const_b(begin(arr), std::cend(arr)); + gsl::span sp_const_c(cbegin(arr), std::end(arr)); + gsl::span sp_const_d(cbegin(arr), std::cend(arr)); + EXPECT_TRUE(sp_const_a.data() == std::begin(arr)); + EXPECT_TRUE(sp_const_b.data() == std::begin(arr)); + EXPECT_TRUE(sp_const_c.data() == std::begin(arr)); + EXPECT_TRUE(sp_const_d.data() == std::begin(arr)); + EXPECT_TRUE(sp_const_a.size() == 3); + EXPECT_TRUE(sp_const_b.size() == 3); + EXPECT_TRUE(sp_const_c.size() == 3); + EXPECT_TRUE(sp_const_d.size() == 3); + } + { + gsl::span sp_dyn_a(arr); + gsl::span sp_dyn_b(stl); + gsl::span sp_dyn_c{stl}; + gsl::span sp_dyn_d{stl}; + EXPECT_TRUE(sp_dyn_a.data() == std::begin(arr)); + EXPECT_TRUE(sp_dyn_b.data() == stl.data()); + EXPECT_TRUE(sp_dyn_a.size() == 3); + EXPECT_TRUE(sp_dyn_b.size() == 3); + + gsl::span sp_three_a(arr); + gsl::span sp_three_b(stl); + EXPECT_TRUE(sp_three_a.data() == std::begin(arr)); + EXPECT_TRUE(sp_three_b.data() == stl.data()); + EXPECT_TRUE(sp_three_a.size() == 3); + EXPECT_TRUE(sp_three_b.size() == 3); + + gsl::span sp_const_w(arr); + gsl::span sp_const_y(stl); + EXPECT_TRUE(sp_const_w.data() == std::begin(arr)); + EXPECT_TRUE(sp_const_y.data() == stl.data()); + EXPECT_TRUE(sp_const_w.size() == 3); + EXPECT_TRUE(sp_const_y.size() == 3); + +#if __cplusplus >= 201703l + gsl::span sp_const_x(std::as_const(arr)); + EXPECT_TRUE(sp_const_x.data() == std::begin(arr)); + EXPECT_TRUE(sp_const_x.size() == 3); + + gsl::span sp_const_z(std::as_const(stl)); + EXPECT_TRUE(sp_const_z.data() == stl.data()); + EXPECT_TRUE(sp_const_z.size() == 3); +#endif // __cplusplus >= 201703l + } + { + const gsl::span orig_dyn(arr); + const gsl::span orig_three(arr); + const gsl::span orig_const_dyn(arr); + const gsl::span orig_const_three(arr); + + gsl::span sp_a(orig_dyn); + gsl::span sp_b(orig_three); + + gsl::span sp_c(orig_three); + + gsl::span sp_d(orig_dyn); + gsl::span sp_e(orig_three); + gsl::span sp_f(orig_const_dyn); + gsl::span sp_g(orig_const_three); + + gsl::span sp_h(orig_three); + gsl::span sp_i(orig_const_three); + + EXPECT_TRUE(sp_a.data() == std::begin(arr)); + EXPECT_TRUE(sp_b.data() == std::begin(arr)); + EXPECT_TRUE(sp_c.data() == std::begin(arr)); + EXPECT_TRUE(sp_d.data() == std::begin(arr)); + EXPECT_TRUE(sp_e.data() == std::begin(arr)); + EXPECT_TRUE(sp_f.data() == std::begin(arr)); + EXPECT_TRUE(sp_g.data() == std::begin(arr)); + EXPECT_TRUE(sp_h.data() == std::begin(arr)); + EXPECT_TRUE(sp_i.data() == std::begin(arr)); + EXPECT_TRUE(sp_a.size() == 3); + EXPECT_TRUE(sp_b.size() == 3); + EXPECT_TRUE(sp_c.size() == 3); + EXPECT_TRUE(sp_d.size() == 3); + EXPECT_TRUE(sp_e.size() == 3); + EXPECT_TRUE(sp_f.size() == 3); + EXPECT_TRUE(sp_g.size() == 3); + EXPECT_TRUE(sp_h.size() == 3); + EXPECT_TRUE(sp_i.size() == 3); + } + { + gsl::span sp_dyn(arr); + gsl::span sp_three(arr); + gsl::span sp_const_dyn(arr); + gsl::span sp_const_three(arr); + + EXPECT_TRUE(sp_dyn.data() == std::begin(arr)); + EXPECT_TRUE(sp_three.data() == std::begin(arr)); + EXPECT_TRUE(sp_const_dyn.data() == std::begin(arr)); + EXPECT_TRUE(sp_const_three.data() == std::begin(arr)); + EXPECT_TRUE(sp_dyn.size() == 3); + EXPECT_TRUE(sp_three.size() == 3); + EXPECT_TRUE(sp_const_dyn.size() == 3); + EXPECT_TRUE(sp_const_three.size() == 3); + + int other[4]{12, 34, 56, 78}; + + sp_dyn = gsl::span{other}; + sp_three = gsl::span{stl}; + sp_const_dyn = gsl::span{other}; + sp_const_three = gsl::span{stl}; + + EXPECT_TRUE(sp_dyn.data() == std::begin(other)); + EXPECT_TRUE(sp_three.data() == stl.data()); + EXPECT_TRUE(sp_const_dyn.data() == std::begin(other)); + EXPECT_TRUE(sp_const_three.data() == stl.data()); + EXPECT_TRUE(sp_dyn.size() == 4); + EXPECT_TRUE(sp_three.size() == 3); + EXPECT_TRUE(sp_const_dyn.size() == 4); + EXPECT_TRUE(sp_const_three.size() == 3); + } + { + gsl::span::iterator it_dyn{}; + + { + gsl::span sp_dyn(arr); + it_dyn = sp_dyn.begin(); + } + + EXPECT_TRUE(*it_dyn == arr[0]); + EXPECT_TRUE(it_dyn[2] == arr[2]); + + gsl::span::iterator it_three{}; + + { + gsl::span sp_three(stl); + it_three = sp_three.begin(); + } + + EXPECT_TRUE(*it_three == stl[0]); + EXPECT_TRUE(it_three[2] == stl[2]); + } + + { + int sequence[9]{10, 20, 30, 40, 50, 60, 70, 80, 90}; + + const gsl::span sp_dyn(sequence); + const gsl::span sp_nine(sequence); + + auto first_3 = sp_dyn.first<3>(); + auto first_4 = sp_nine.first<4>(); + auto first_5 = sp_dyn.first(5); + auto first_6 = sp_nine.first(6); + static_assert(noexcept(sp_dyn.first<3>()), "noexcept(sp_dyn.first<3>())"); // strengthened + static_assert(noexcept(sp_nine.first<4>()), "noexcept(sp_nine.first<4>())"); // strengthened + static_assert(noexcept(sp_dyn.first(5)), "noexcept(sp_dyn.first(5))"); // strengthened + static_assert(noexcept(sp_nine.first(6)), "noexcept(sp_nine.first(6))"); // strengthened + static_assert(is_same>::value, + "is_same>::value"); + static_assert(is_same>::value, + "is_same>::value"); + static_assert(is_same>::value, + "is_same>::value"); + static_assert(is_same>::value, + "is_same>::value"); + EXPECT_TRUE(first_3.data() == std::begin(sequence)); + EXPECT_TRUE(first_4.data() == std::begin(sequence)); + EXPECT_TRUE(first_5.data() == std::begin(sequence)); + EXPECT_TRUE(first_6.data() == std::begin(sequence)); + EXPECT_TRUE(first_3.size() == 3); + EXPECT_TRUE(first_4.size() == 4); + EXPECT_TRUE(first_5.size() == 5); + EXPECT_TRUE(first_6.size() == 6); + + auto last_3 = sp_dyn.last<3>(); + auto last_4 = sp_nine.last<4>(); + auto last_5 = sp_dyn.last(5); + auto last_6 = sp_nine.last(6); + static_assert(noexcept(sp_dyn.last<3>()), "noexcept(sp_dyn.last<3>())"); // strengthened + static_assert(noexcept(sp_nine.last<4>()), "noexcept(sp_nine.last<4>())"); // strengthened + static_assert(noexcept(sp_dyn.last(5)), "noexcept(sp_dyn.last(5))"); // strengthened + static_assert(noexcept(sp_nine.last(6)), "noexcept(sp_nine.last(6))"); // strengthened + static_assert(is_same>::value, + "is_same>::value"); + static_assert(is_same>::value, + "is_same>::value"); + static_assert(is_same>::value, + "is_same>::value"); + static_assert(is_same>::value, + "is_same>::value"); + EXPECT_TRUE(last_3.data() == std::begin(sequence) + 6); + EXPECT_TRUE(last_4.data() == std::begin(sequence) + 5); + EXPECT_TRUE(last_5.data() == std::begin(sequence) + 4); + EXPECT_TRUE(last_6.data() == std::begin(sequence) + 3); + EXPECT_TRUE(last_3.size() == 3); + EXPECT_TRUE(last_4.size() == 4); + EXPECT_TRUE(last_5.size() == 5); + EXPECT_TRUE(last_6.size() == 6); + + auto offset_3 = sp_dyn.subspan<3>(); + auto offset_4 = sp_nine.subspan<4>(); + auto offset_5 = sp_dyn.subspan(5); + auto offset_6 = sp_nine.subspan(6); + static_assert(noexcept(sp_dyn.subspan<3>()), + "noexcept(sp_dyn.subspan<3>())"); // strengthened + static_assert(noexcept(sp_nine.subspan<4>()), + "noexcept(sp_nine.subspan<4>())"); // strengthened + static_assert(noexcept(sp_dyn.subspan(5)), "noexcept(sp_dyn.subspan(5))"); // strengthened + static_assert(noexcept(sp_nine.subspan(6)), "noexcept(sp_nine.subspan(6))"); // strengthened + static_assert(is_same>::value, + "is_same>::value"); + static_assert(is_same>::value, + "is_same>::value"); + static_assert(is_same>::value, + "is_same>::value"); + static_assert(is_same>::value, + "is_same>::value"); + EXPECT_TRUE(offset_3.data() == std::begin(sequence) + 3); + EXPECT_TRUE(offset_4.data() == std::begin(sequence) + 4); + EXPECT_TRUE(offset_5.data() == std::begin(sequence) + 5); + EXPECT_TRUE(offset_6.data() == std::begin(sequence) + 6); + EXPECT_TRUE(offset_3.size() == 6); + EXPECT_TRUE(offset_4.size() == 5); + EXPECT_TRUE(offset_5.size() == 4); + EXPECT_TRUE(offset_6.size() == 3); + + auto subspan_3 = sp_dyn.subspan<3, 2>(); + auto subspan_4 = sp_nine.subspan<4, 2>(); + auto subspan_5 = sp_dyn.subspan(5, 2); + auto subspan_6 = sp_nine.subspan(6, 2); + static_assert(noexcept(sp_dyn.subspan<3, 2>()), + "noexcept(sp_dyn.subspan<3, 2>())"); // strengthened + static_assert(noexcept(sp_nine.subspan<4, 2>()), + "noexcept(sp_nine.subspan<4, 2>())"); // strengthened + static_assert(noexcept(sp_dyn.subspan(5, 2)), + "noexcept(sp_dyn.subspan(5, 2))"); // strengthened + static_assert(noexcept(sp_nine.subspan(6, 2)), + "noexcept(sp_nine.subspan(6, 2))"); // strengthened + static_assert(is_same>::value, + "is_same>::value"); + static_assert(is_same>::value, + "is_same>::value"); + static_assert(is_same>::value, + "is_same>::value"); + static_assert(is_same>::value, + "is_same>::value"); + EXPECT_TRUE(subspan_3.data() == std::begin(sequence) + 3); + EXPECT_TRUE(subspan_4.data() == std::begin(sequence) + 4); + EXPECT_TRUE(subspan_5.data() == std::begin(sequence) + 5); + EXPECT_TRUE(subspan_6.data() == std::begin(sequence) + 6); + EXPECT_TRUE(subspan_3.size() == 2); + EXPECT_TRUE(subspan_4.size() == 2); + EXPECT_TRUE(subspan_5.size() == 2); + EXPECT_TRUE(subspan_6.size() == 2); + + static_assert(noexcept(sp_dyn.size()), "noexcept(sp_dyn.size())"); + static_assert(noexcept(sp_dyn.size_bytes()), "noexcept(sp_dyn.size_bytes())"); + static_assert(noexcept(sp_dyn.empty()), "noexcept(sp_dyn.empty())"); + static_assert(noexcept(sp_dyn[0]), "noexcept(sp_dyn[0])"); // strengthened + static_assert(noexcept(sp_dyn.front()), "noexcept(sp_dyn.front())"); // strengthened + static_assert(noexcept(sp_dyn.back()), "noexcept(sp_dyn.back())"); // strengthened + static_assert(noexcept(sp_dyn.data()), "noexcept(sp_dyn.data())"); + static_assert(noexcept(sp_dyn.begin()), "noexcept(sp_dyn.begin())"); + static_assert(noexcept(sp_dyn.end()), "noexcept(sp_dyn.end())"); + static_assert(noexcept(sp_dyn.cbegin()), "noexcept(sp_dyn.cbegin())"); + static_assert(noexcept(sp_dyn.cend()), "noexcept(sp_dyn.cend())"); + static_assert(noexcept(sp_dyn.rbegin()), "noexcept(sp_dyn.rbegin())"); + static_assert(noexcept(sp_dyn.rend()), "noexcept(sp_dyn.rend())"); + static_assert(noexcept(sp_dyn.crbegin()), "noexcept(sp_dyn.crbegin())"); + static_assert(noexcept(sp_dyn.crend()), "noexcept(sp_dyn.crend())"); + + static_assert(noexcept(sp_nine.size()), "noexcept(sp_nine.size())"); + static_assert(noexcept(sp_nine.size_bytes()), "noexcept(sp_nine.size_bytes())"); + static_assert(noexcept(sp_nine.empty()), "noexcept(sp_nine.empty())"); + static_assert(noexcept(sp_nine[0]), "noexcept(sp_nine[0])"); // strengthened + static_assert(noexcept(sp_nine.front()), "noexcept(sp_nine.front())"); // strengthened + static_assert(noexcept(sp_nine.back()), "noexcept(sp_nine.back())"); // strengthened + static_assert(noexcept(sp_nine.data()), "noexcept(sp_nine.data())"); + static_assert(noexcept(sp_nine.begin()), "noexcept(sp_nine.begin())"); + static_assert(noexcept(sp_nine.end()), "noexcept(sp_nine.end())"); + static_assert(noexcept(sp_nine.cbegin()), "noexcept(sp_nine.cbegin())"); + static_assert(noexcept(sp_nine.cend()), "noexcept(sp_nine.cend())"); + static_assert(noexcept(sp_nine.rbegin()), "noexcept(sp_nine.rbegin())"); + static_assert(noexcept(sp_nine.rend()), "noexcept(sp_nine.rend())"); + static_assert(noexcept(sp_nine.crbegin()), "noexcept(sp_nine.crbegin())"); + static_assert(noexcept(sp_nine.crend()), "noexcept(sp_nine.crend())"); + + EXPECT_TRUE(sp_dyn.size() == 9); + EXPECT_TRUE(sp_nine.size() == 9); + + EXPECT_TRUE(sp_dyn.size_bytes() == 9 * sizeof(int)); + EXPECT_TRUE(sp_nine.size_bytes() == 9 * sizeof(int)); + + EXPECT_TRUE(!sp_dyn.empty()); + EXPECT_TRUE(!sp_nine.empty()); + + EXPECT_TRUE(sp_dyn[0] == 10); + EXPECT_TRUE(sp_nine[0] == 10); + EXPECT_TRUE(sp_dyn[8] == 90); + EXPECT_TRUE(sp_nine[8] == 90); + + EXPECT_TRUE(sp_dyn.front() == 10); + EXPECT_TRUE(sp_nine.front() == 10); + + EXPECT_TRUE(sp_dyn.back() == 90); + EXPECT_TRUE(sp_nine.back() == 90); + + EXPECT_TRUE(&sp_dyn.front() == std::begin(sequence)); + EXPECT_TRUE(&sp_nine.front() == std::begin(sequence)); + EXPECT_TRUE(&sp_dyn[4] == std::begin(sequence) + 4); + EXPECT_TRUE(&sp_nine[4] == std::begin(sequence) + 4); + EXPECT_TRUE(&sp_dyn.back() == std::begin(sequence) + 8); + EXPECT_TRUE(&sp_nine.back() == std::begin(sequence) + 8); + + EXPECT_TRUE(sp_dyn.data() == std::begin(sequence)); + EXPECT_TRUE(sp_nine.data() == std::begin(sequence)); + + EXPECT_TRUE(*sp_dyn.begin() == 10); + EXPECT_TRUE(*sp_nine.begin() == 10); + + EXPECT_TRUE(sp_dyn.end()[-2] == 80); + EXPECT_TRUE(sp_nine.end()[-2] == 80); + + EXPECT_TRUE(*sp_dyn.cbegin() == 10); + EXPECT_TRUE(*sp_nine.cbegin() == 10); + + EXPECT_TRUE(sp_dyn.cend()[-2] == 80); + EXPECT_TRUE(sp_nine.cend()[-2] == 80); + + EXPECT_TRUE(*sp_dyn.rbegin() == 90); + EXPECT_TRUE(*sp_nine.rbegin() == 90); + + EXPECT_TRUE(sp_dyn.rend()[-2] == 20); + EXPECT_TRUE(sp_nine.rend()[-2] == 20); + + EXPECT_TRUE(*sp_dyn.crbegin() == 90); + EXPECT_TRUE(*sp_nine.crbegin() == 90); + + EXPECT_TRUE(sp_dyn.crend()[-2] == 20); + EXPECT_TRUE(sp_nine.crend()[-2] == 20); + + static_assert(is_same::iterator>::value, + "is_same::iterator>::value"); + static_assert(is_same::iterator>::value, + "is_same::iterator>::value"); + static_assert(is_same::iterator>::value, + "is_same::iterator>::value"); + static_assert(is_same::iterator>::value, + "is_same::iterator>::value"); + static_assert(is_same::const_iterator>::value, + "is_same::const_iterator>::value"); + static_assert( + is_same::const_iterator>::value, + "is_same::const_iterator>::value"); + static_assert(is_same::const_iterator>::value, + "is_same::const_iterator>::value"); + static_assert( + is_same::const_iterator>::value, + "is_same::const_iterator>::value"); + static_assert( + is_same::reverse_iterator>::value, + "is_same::reverse_iterator>::value"); + static_assert( + is_same::reverse_iterator>::value, + "is_same::reverse_iterator>::value"); + static_assert(is_same::reverse_iterator>::value, + "is_same::reverse_iterator>::value"); + static_assert( + is_same::reverse_iterator>::value, + "is_same::reverse_iterator>::value"); + static_assert( + is_same::const_reverse_iterator>::value, + "is_same::const_reverse_iterator>::value"); + static_assert( + is_same::const_reverse_iterator>::value, + "is_same::const_reverse_iterator>::value"); + static_assert( + is_same::const_reverse_iterator>::value, + "is_same::const_reverse_iterator>::value"); + static_assert( + is_same::const_reverse_iterator>::value, + "is_same::const_reverse_iterator>::value"); + } + { + int sequence[9]{10, 20, 30, 40, 50, 60, 70, 80, 90}; + + constexpr size_t SizeBytes = sizeof(sequence); + + const gsl::span sp_dyn(sequence); + const gsl::span sp_nine(sequence); + const gsl::span sp_const_dyn(sequence); + const gsl::span sp_const_nine(sequence); + + static_assert(noexcept(as_bytes(sp_dyn)), "noexcept(as_bytes(sp_dyn))"); + static_assert(noexcept(as_bytes(sp_nine)), "noexcept(as_bytes(sp_nine))"); + static_assert(noexcept(as_bytes(sp_const_dyn)), "noexcept(as_bytes(sp_const_dyn))"); + static_assert(noexcept(as_bytes(sp_const_nine)), "noexcept(as_bytes(sp_const_nine))"); + static_assert(noexcept(as_writable_bytes(sp_dyn)), "noexcept(as_writable_bytes(sp_dyn))"); + static_assert(noexcept(as_writable_bytes(sp_nine)), "noexcept(as_writable_bytes(sp_nine))"); + + auto sp_1 = as_bytes(sp_dyn); + auto sp_2 = as_bytes(sp_nine); + auto sp_3 = as_bytes(sp_const_dyn); + auto sp_4 = as_bytes(sp_const_nine); + auto sp_5 = as_writable_bytes(sp_dyn); + auto sp_6 = as_writable_bytes(sp_nine); + + static_assert(is_same>::value, + "is_same>::value"); + static_assert(is_same>::value, + "is_same>::value"); + static_assert(is_same>::value, + "is_same>::value"); + static_assert(is_same>::value, + "is_same>::value"); + static_assert(is_same>::value, + "is_same>::value"); + static_assert(is_same>::value, + "is_same>::value"); + + EXPECT_TRUE(sp_1.data() == reinterpret_cast(begin(sequence))); + EXPECT_TRUE(sp_2.data() == reinterpret_cast(begin(sequence))); + EXPECT_TRUE(sp_3.data() == reinterpret_cast(begin(sequence))); + EXPECT_TRUE(sp_4.data() == reinterpret_cast(begin(sequence))); + EXPECT_TRUE(sp_5.data() == reinterpret_cast(begin(sequence))); + EXPECT_TRUE(sp_6.data() == reinterpret_cast(begin(sequence))); + + EXPECT_TRUE(sp_1.size() == SizeBytes); + EXPECT_TRUE(sp_2.size() == SizeBytes); + EXPECT_TRUE(sp_3.size() == SizeBytes); + EXPECT_TRUE(sp_4.size() == SizeBytes); + EXPECT_TRUE(sp_5.size() == SizeBytes); + EXPECT_TRUE(sp_6.size() == SizeBytes); + } +} + +// assertions for span's definition +static_assert(std::is_same::value, + "gsl::dynamic_extent must be respresented as std::size_t"); +static_assert(gsl::dynamic_extent == static_cast(-1), + "gsl::dynamic_extent must be defined as the max value of std::size_t"); + +static_assert(std::is_same::extent), const std::size_t>::value, + "Ensure that the type of gsl::span::extent is std::size_t"); +static_assert(gsl::span::extent == gsl::dynamic_extent, + "gsl::span::extent should be equivalent to gsl::dynamic_extent"); + +static_assert(std::is_same::extent), const std::size_t>::value, + "Ensure that the type of gsl::span::extent is std::size_t"); +static_assert(gsl::span::extent == 3, "Ensure that span::extent is equal to 3"); + +static_assert(std::is_same::element_type, int>::value, + "span::element_type should be int"); +static_assert(std::is_same::value_type, int>::value, + "span::value_type should be int"); +static_assert(std::is_same::size_type, std::size_t>::value, + "span::size_type should be std::size_t"); +static_assert(std::is_same::difference_type, ptrdiff_t>::value, + "span::difference_type should be std::ptrdiff_t"); +static_assert(std::is_same::pointer, int*>::value, + "span::pointer should be int*"); +static_assert(std::is_same::const_pointer, const int*>::value, + "span::const_pointer should be const int*"); +static_assert(std::is_same::reference, int&>::value, + "span::reference should be int&"); +static_assert(std::is_same::const_reference, const int&>::value, + "span::const_reference should be const int&"); + +static_assert(std::is_same::element_type, int>::value, + "span::element_type should be int"); +static_assert(std::is_same::value_type, int>::value, + "span::value_type should be int"); +static_assert(std::is_same::size_type, std::size_t>::value, + "span::size_type should be std::size_t"); +static_assert(std::is_same::difference_type, ptrdiff_t>::value, + "span::difference_type should be std::ptrdiff_t"); +static_assert(std::is_same::pointer, int*>::value, + "span::pointer should be int*"); +static_assert(std::is_same::const_pointer, const int*>::value, + "span::const_pointer should be const int*"); +static_assert(std::is_same::reference, int&>::value, + "span::reference should be int&"); +static_assert(std::is_same::const_reference, const int&>::value, + "span::const_reference should be const int&"); + +static_assert(std::is_same::element_type, const int>::value, + "span::element_type should be const int"); +static_assert(std::is_same::value_type, int>::value, + "span::value_type should be int"); +static_assert(std::is_same::size_type, std::size_t>::value, + "span::size_type should be size_t"); +static_assert(std::is_same::difference_type, ptrdiff_t>::value, + "span::difference_type should be ptrdiff_t"); +static_assert(std::is_same::pointer, const int*>::value, + "span::pointer should be const int*"); +static_assert(std::is_same::const_pointer, const int*>::value, + "span::const_pointer should be const int*"); +static_assert(std::is_same::reference, const int&>::value, + "span::reference should be const int&"); +static_assert(std::is_same::const_reference, const int&>::value, + "span::const_reference should be const int&"); + +static_assert(std::is_same::element_type, const int>::value, + "span::element_type should be const int"); +static_assert(std::is_same::value_type, int>::value, + "span::value_type should be int"); +static_assert(std::is_same::size_type, std::size_t>::value, + "span::size_type should be size_t"); +static_assert(std::is_same::difference_type, ptrdiff_t>::value, + "span::difference_type should be ptrdiff_t"); +static_assert(std::is_same::pointer, const int*>::value, + "span::pointer should be const int*"); +static_assert(std::is_same::const_pointer, const int*>::value, + "span::const_pointer should be const int*"); +static_assert(std::is_same::reference, const int&>::value, + "span::reference should be const int&"); +static_assert(std::is_same::const_reference, const int&>::value, + "span::const_reference should be const int&"); + +// assertions for span_iterator +static_assert(std::is_same::iterator>::pointer, int*>::value, + "span::iterator's pointer should be int*"); +static_assert( + std::is_same::const_iterator>::pointer, const int*>::value, + "span::const_iterator's pointer should be const int*"); +static_assert( + std::is_same::reverse_iterator, + std::reverse_iterator::iterator>>::value, + "span::reverse_iterator should equal std::reverse_iterator::iterator>"); +static_assert(std::is_same::const_reverse_iterator, + std::reverse_iterator::const_iterator>>::value, + "span::const_reverse_iterator should equal " + "std::reverse_iterator::const_iterator>"); + +static_assert(std::is_same::iterator>::pointer, int*>::value, + "span::iterator's pointer should be int*"); +static_assert(std::is_same::const_iterator>::pointer, + const int*>::value, + "span::const_iterator's pointer should be const int*"); +static_assert( + std::is_same::reverse_iterator, + std::reverse_iterator::iterator>>::value, + "span::reverse_iterator should equal std::reverse_iterator::iterator>"); +static_assert(std::is_same::const_reverse_iterator, + std::reverse_iterator::const_iterator>>::value, + "span::const_reverse_iterator should equal std::reverse_iterator::const_iterator>"); + +static_assert( + std::is_same::iterator>::pointer, const int*>::value, + "span::iterator's pointer should be int*"); +static_assert(std::is_same::const_iterator>::pointer, + const int*>::value, + "span::const_iterator's pointer should be const int*"); +static_assert(std::is_same::reverse_iterator, + std::reverse_iterator::iterator>>::value, + "span::reverse_iterator should equal std::reverse_iterator::iterator>"); +static_assert(std::is_same::const_reverse_iterator, + std::reverse_iterator::const_iterator>>::value, + "span::const_reverse_iterator should equal " + "std::reverse_iterator::const_iterator>"); + +static_assert(std::is_same::iterator>::pointer, + const int*>::value, + "span::iterator's pointer should be int*"); +static_assert(std::is_same::const_iterator>::pointer, + const int*>::value, + "span::const_iterator's pointer should be const int*"); +static_assert(std::is_same::reverse_iterator, + std::reverse_iterator::iterator>>::value, + "span::reverse_iterator should equal std::reverse_iterator::iterator>"); +static_assert(std::is_same::const_reverse_iterator, + std::reverse_iterator::const_iterator>>::value, + "span::const_reverse_iterator should equal " + "std::reverse_iterator::const_iterator>"); + +// copyability assertions +static_assert(std::is_trivially_copyable>::value, + "span should be trivially copyable"); +static_assert(std::is_trivially_copyable::iterator>::value, + "span::iterator should be trivially copyable"); +static_assert(std::is_trivially_copyable::const_iterator>::value, + "span::const_iterator should be trivially copyable"); + +static_assert(std::is_trivially_copyable>::value, + "span should be trivially copyable"); +static_assert(std::is_trivially_copyable::iterator>::value, + "span::iterator should be trivially copyable"); +static_assert(std::is_trivially_copyable::const_iterator>::value, + "span::const_iterator should be trivially copyable"); + +static_assert(std::is_trivially_copyable>::value, + "span should be trivially copyable"); +static_assert(std::is_trivially_copyable::iterator>::value, + "span::iterator should be trivially copyable"); +static_assert(std::is_trivially_copyable::const_iterator>::value, + "span::const_iterator should be trivially copyable"); + +static_assert(std::is_trivially_copyable>::value, + "span should be trivially copyable"); +static_assert(std::is_trivially_copyable::iterator>::value, + "span::iterator should be trivially copyable"); +static_assert(std::is_trivially_copyable::const_iterator>::value, + "span::const_iterator should be trivially copyable"); + +// nothrow constructible assertions +static_assert(std::is_nothrow_constructible, int*, std::size_t>::value, + "std::is_nothrow_constructible, int*, std::size_t>"); +static_assert(std::is_nothrow_constructible, int*, std::uint16_t>::value, + "std::is_nothrow_constructible, int*, std::uint16_t>"); +static_assert(std::is_nothrow_constructible, int*, int*>::value, + "std::is_nothrow_constructible, int*, int*>"); +static_assert(std::is_nothrow_constructible, int (&)[3]>::value, + "std::is_nothrow_constructible, int(&)[3]>"); +static_assert(std::is_nothrow_constructible, const gsl::span&>::value, + "std::is_nothrow_constructible, const gsl::span&>"); +static_assert(std::is_nothrow_constructible, const gsl::span&>::value, + "std::is_nothrow_constructible, const gsl::span&>"); +static_assert(std::is_nothrow_constructible, const gsl::span&>::value, + "std::is_nothrow_constructible, const gsl::span&>"); +static_assert(std::is_nothrow_constructible, std::array&>::value, + "std::is_nothrow_constructible, std::array&>"); + +static_assert(std::is_nothrow_constructible, int*, std::size_t>::value, + "std::is_nothrow_constructible, int*, std::size_t>"); +static_assert(std::is_nothrow_constructible, int*, std::uint16_t>::value, + "std::is_nothrow_constructible, int*, std::uint16_t>"); +static_assert(std::is_nothrow_constructible, int*, int*>::value, + "std::is_nothrow_constructible, int*, int*>"); +static_assert(std::is_nothrow_constructible, int (&)[3]>::value, + "std::is_nothrow_constructible, int(&)[3]>"); +static_assert(std::is_nothrow_constructible, const gsl::span&>::value, + "std::is_nothrow_constructible, const gsl::span&>"); +static_assert(std::is_nothrow_constructible, std::array&>::value, + "std::is_nothrow_constructible, std::array&>"); + +static_assert(std::is_nothrow_constructible, int*, std::size_t>::value, + "std::is_nothrow_constructible, int*, std::size_t>"); +static_assert(std::is_nothrow_constructible, int*, int*>::value, + "std::is_nothrow_constructible, int*, int*>"); +static_assert(std::is_nothrow_constructible, int*, const int*>::value, + "std::is_nothrow_constructible, int*, const int*>"); +static_assert(std::is_nothrow_constructible, int (&)[3]>::value, + "std::is_nothrow_constructible, int(&)[3]>"); +static_assert(std::is_nothrow_constructible, const int*, int*>::value, + "std::is_nothrow_constructible, const int*, int*>"); +static_assert(std::is_nothrow_constructible, const int*, const int*>::value, + "std::is_nothrow_constructible, const int*, const int*>"); +static_assert(std::is_nothrow_constructible, const int*, std::size_t>::value, + "std::is_nothrow_constructible, const int*, std::size_t>"); +static_assert(std::is_nothrow_constructible, const int (&)[3]>::value, + "std::is_nothrow_constructible, const int(&)[3]>"); +static_assert(std::is_nothrow_constructible, const gsl::span&>::value, + "std::is_nothrow_constructible, const gsl::span&>"); +static_assert(std::is_nothrow_constructible, const gsl::span&>::value, + "std::is_nothrow_constructible, const gsl::span&>"); +static_assert( + std::is_nothrow_constructible, const gsl::span&>::value, + "std::is_nothrow_constructible, const gsl::span&>"); +static_assert( + std::is_nothrow_constructible, const gsl::span&>::value, + "std::is_nothrow_constructible, const gsl::span&>"); +static_assert( + std::is_nothrow_constructible, const gsl::span&>::value, + "std::is_nothrow_constructible, const gsl::span&>"); +static_assert( + std::is_nothrow_constructible, const gsl::span&>::value, + "std::is_nothrow_constructible, const gsl::span&>"); +static_assert(std::is_nothrow_constructible, std::array&>::value, + "std::is_nothrow_constructible, std::array&>"); +static_assert(std::is_nothrow_constructible, const std::array&>::value, + "std::is_nothrow_constructible, const std::array&>"); + +static_assert( + std::is_nothrow_constructible, const gsl::span&>::value, + "std::is_nothrow_constructible, const gsl::span&>"); +static_assert( + std::is_nothrow_constructible, const gsl::span&>::value, + "std::is_nothrow_constructible, const gsl::span&>"); + +static_assert(std::is_nothrow_constructible, Base (&)[3]>::value, + "std::is_nothrow_constructible, Base(&)[3]>"); +static_assert(std::is_nothrow_constructible, const gsl::span&>::value, + "std::is_nothrow_constructible, const gsl::span&>"); +static_assert(std::is_nothrow_constructible, const gsl::span&>::value, + "std::is_nothrow_constructible, const gsl::span&>"); +static_assert(std::is_nothrow_constructible, std::array&>::value, + "std::is_nothrow_constructible, std::array&>"); + +static_assert(std::is_nothrow_constructible, Base (&)[3]>::value, + "std::is_nothrow_constructible, Base(&)[3]>"); +static_assert(std::is_nothrow_constructible, const gsl::span&>::value, + "std::is_nothrow_constructible, const gsl::span&>"); +static_assert(std::is_nothrow_constructible, std::array&>::value, + "std::is_nothrow_constructible, std::array&>"); + +static_assert(std::is_nothrow_constructible, Base (&)[3]>::value, + "std::is_nothrow_constructible, Base(&)[3]>"); +static_assert(std::is_nothrow_constructible, const Base (&)[3]>::value, + "std::is_nothrow_constructible, const Base(&)[3]>"); +static_assert(std::is_nothrow_constructible, const gsl::span&>::value, + "std::is_nothrow_constructible, const gsl::span&>"); +static_assert( + std::is_nothrow_constructible, const gsl::span&>::value, + "std::is_nothrow_constructible, const gsl::span&>"); +static_assert( + std::is_nothrow_constructible, const gsl::span&>::value, + "std::is_nothrow_constructible, const gsl::span&>"); +static_assert( + std::is_nothrow_constructible, const gsl::span&>::value, + "std::is_nothrow_constructible, const gsl::span&>"); +static_assert(std::is_nothrow_constructible, std::array&>::value, + "std::is_nothrow_constructible, std::array&>"); +static_assert( + std::is_nothrow_constructible, const std::array&>::value, + "std::is_nothrow_constructible, const std::array&>"); + +static_assert( + std::is_nothrow_constructible, const gsl::span&>::value, + "std::is_nothrow_constructible, const gsl::span&>"); +static_assert( + std::is_nothrow_constructible, const gsl::span&>::value, + "std::is_nothrow_constructible, const gsl::span&>"); + +// non-constructible assertions +static_assert(!std::is_constructible, const int*, int*>::value, + "!std::is_constructible, const int*, int*>"); +static_assert(!std::is_constructible, const int*, const int*>::value, + "!std::is_constructible, const int*, const int*>"); +static_assert(!std::is_constructible, const int*, double*>::value, + "!std::is_constructible, const int*, double*>"); +static_assert(!std::is_constructible, const int*, std::size_t>::value, + "!std::is_constructible, const int*, std::size_t>"); +static_assert(!std::is_constructible, const int (&)[3]>::value, + "!std::is_constructible, const int(&)[3]>"); +static_assert(!std::is_constructible, double*, int*>::value, + "!std::is_constructible, double*, int*>"); +static_assert(!std::is_constructible, double*, const int*>::value, + "!std::is_constructible, double*, const int*>"); +static_assert(!std::is_constructible, double*, double*>::value, + "!std::is_constructible, double*, double*>"); +static_assert(!std::is_constructible, double*, std::size_t>::value, + "!std::is_constructible, double*, std::size_t>"); +static_assert(!std::is_constructible, double (&)[3]>::value, + "!std::is_constructible, double(&)[3]>"); +static_assert(!std::is_constructible, int*, double*>::value, + "!std::is_constructible, int*, double*>"); +static_assert(!std::is_constructible, std::size_t, int*>::value, + "!std::is_constructible, std::size_t, int*>"); +static_assert(!std::is_constructible, std::size_t, std::size_t>::value, + "!std::is_constructible, std::size_t, std::size_t>"); +static_assert(!std::is_constructible, const gsl::span&>::value, + "!std::is_constructible, const gsl::span&>"); +static_assert(!std::is_constructible, const gsl::span&>::value, + "!std::is_constructible, const gsl::span&>"); +static_assert(!std::is_constructible, const gsl::span&>::value, + "!std::is_constructible, const gsl::span&>"); +static_assert(!std::is_constructible, const gsl::span&>::value, + "!std::is_constructible, const gsl::span&>"); +static_assert(!std::is_constructible, std::array&>::value, + "!std::is_constructible, std::array&>"); +static_assert(!std::is_constructible, const std::array&>::value, + "!std::is_constructible, const std::array&>"); + +static_assert(!std::is_constructible, int*, double*>::value, + "!std::is_constructible, int*, double*>"); +static_assert(!std::is_constructible, int (&)[500]>::value, + "!std::is_constructible, int(&)[500]>"); +static_assert(!std::is_constructible, const int*, int*>::value, + "!std::is_constructible, const int*, int*>"); +static_assert(!std::is_constructible, const int*, const int*>::value, + "!std::is_constructible, const int*, const int*>"); +static_assert(!std::is_constructible, const int*, std::size_t>::value, + "!std::is_constructible, const int*, std::size_t>"); +static_assert(!std::is_constructible, const int*, double*>::value, + "!std::is_constructible, const int*, double*>"); +static_assert(!std::is_constructible, const int (&)[3]>::value, + "!std::is_constructible, const int(&)[3]>"); +static_assert(!std::is_constructible, double*, std::size_t>::value, + "!std::is_constructible, double*, std::size_t>"); +static_assert(!std::is_constructible, double*, int*>::value, + "!std::is_constructible, double*, int*>"); +static_assert(!std::is_constructible, double*, const int*>::value, + "!std::is_constructible, double*, const int*>"); +static_assert(!std::is_constructible, double*, double*>::value, + "!std::is_constructible, double*, double*>"); +static_assert(!std::is_constructible, double (&)[3]>::value, + "!std::is_constructible, double(&)[3]>"); + +static_assert(!std::is_constructible, std::size_t, int*>::value, + "!std::is_constructible, std::size_t, int*>"); +static_assert(!std::is_constructible, std::size_t, std::size_t>::value, + "!std::is_constructible, std::size_t, std::size_t>"); +static_assert(!std::is_constructible, std::array&>::value, + "!std::is_constructible, std::array&>"); +static_assert(!std::is_constructible, std::array&>::value, + "!std::is_constructible, std::array&>"); +static_assert(!std::is_constructible, const std::array&>::value, + "!std::is_constructible, const std::array&>"); +static_assert(!std::is_constructible, const gsl::span&>::value, + "!std::is_constructible, const gsl::span&>"); +static_assert(!std::is_constructible, const gsl::span&>::value, + "!std::is_constructible, const gsl::span&>"); +static_assert(!std::is_constructible, const gsl::span&>::value, + "!std::is_constructible, const gsl::span&>"); +static_assert(!std::is_constructible, const gsl::span&>::value, + "!std::is_constructible, const gsl::span&>"); +static_assert(!std::is_constructible, const gsl::span&>::value, + "!std::is_constructible, const gsl::span&>"); +static_assert(!std::is_constructible, const gsl::span&>::value, + "!std::is_constructible, const gsl::span&>"); + +static_assert(!std::is_constructible, double (&)[3]>::value, + "!std::is_constructible, double(&)[3]>"); +static_assert(!std::is_constructible, std::array&>::value, + "!std::is_constructible, std::array&>"); +static_assert(!std::is_constructible, const gsl::span&>::value, + "!std::is_constructible, const gsl::span&>"); + +static_assert(!std::is_constructible, const gsl::span&>::value, + "!std::is_constructible, const gsl::span&>"); +static_assert(!std::is_constructible, const gsl::span&>::value, + "!std::is_constructible, const gsl::span&>"); +static_assert(!std::is_constructible, const gsl::span&>::value, + "!std::is_constructible, const gsl::span&>"); +static_assert( + !std::is_constructible, const gsl::span&>::value, + "!std::is_constructible, const gsl::span&>"); +static_assert(!std::is_constructible, const gsl::span&>::value, + "!std::is_constructible, const gsl::span&>"); + +static_assert(!std::is_constructible, Derived (&)[3]>::value, + "!std::is_constructible, Derived(&)[3]>"); +static_assert(!std::is_constructible, std::array&>::value, + "!std::is_constructible, std::array&>"); +static_assert(!std::is_constructible, std::vector&>::value, + "!std::is_constructible, std::vector&>"); +static_assert(!std::is_constructible, const gsl::span&>::value, + "!std::is_constructible, const gsl::span&>"); +static_assert(!std::is_constructible, const gsl::span&>::value, + "!std::is_constructible, const gsl::span&>"); + +static_assert(!std::is_constructible, const gsl::span&>::value, + "!std::is_constructible, const gsl::span&>"); +static_assert(!std::is_constructible, Derived (&)[3]>::value, + "!std::is_constructible, Derived(&)[3]>"); +static_assert(!std::is_constructible, std::array&>::value, + "!std::is_constructible, std::array&>"); + +static_assert(!std::is_constructible, Derived (&)[3]>::value, + "!std::is_constructible, Derived(&)[3]>"); +static_assert(!std::is_constructible, const Derived (&)[3]>::value, + "!std::is_constructible, const Derived(&)[3]>"); +static_assert(!std::is_constructible, std::array&>::value, + "!std::is_constructible, std::array&>"); +static_assert(!std::is_constructible, const std::array&>::value, + "!std::is_constructible, const std::array&>"); +static_assert(!std::is_constructible, const gsl::span&>::value, + "!std::is_constructible, const gsl::span&>"); +static_assert(!std::is_constructible, const gsl::span&>::value, + "!std::is_constructible, const gsl::span&>"); +static_assert(!std::is_constructible, const gsl::span&>::value, + "!std::is_constructible, const gsl::span&>"); +static_assert( + !std::is_constructible, const gsl::span&>::value, + "!std::is_constructible, const gsl::span&>"); + +static_assert(!std::is_constructible, const gsl::span&>::value, + "!std::is_constructible, const gsl::span&>"); +static_assert( + !std::is_constructible, const gsl::span&>::value, + "!std::is_constructible, const gsl::span&>"); + +static_assert(!std::is_constructible, std::array&>::value, + "!std::is_constructible, std::array&>"); +static_assert(!std::is_constructible, const std::array&>::value, + "!std::is_constructible, const std::array&>"); + +// no throw copy constructor +static_assert(std::is_nothrow_copy_constructible>::value, + "std::is_nothrow_copy_constructible>"); +static_assert(std::is_nothrow_copy_constructible>::value, + "std::is_nothrow_copy_constructible>"); +static_assert(std::is_nothrow_copy_constructible>::value, + "std::is_nothrow_copy_constructible>"); +static_assert(std::is_nothrow_copy_constructible>::value, + "std::is_nothrow_copy_constructible>"); + +// no throw copy assignment +static_assert(std::is_nothrow_copy_assignable>::value, + "std::is_nothrow_copy_assignable>"); +static_assert(std::is_nothrow_copy_assignable>::value, + "std::is_nothrow_copy_assignable>"); +static_assert(std::is_nothrow_copy_assignable>::value, + "std::is_nothrow_copy_assignable>"); +static_assert(std::is_nothrow_copy_assignable>::value, + "std::is_nothrow_copy_assignable>"); + +// no throw destruction +static_assert(std::is_nothrow_destructible>::value, + "std::is_nothrow_destructible>"); +static_assert(std::is_nothrow_destructible>::value, + "std::is_nothrow_destructible>"); +static_assert(std::is_nothrow_destructible>::value, + "std::is_nothrow_destructible>"); + +// conversions +static_assert(std::is_convertible>::value, + "std::is_convertible>"); +static_assert(std::is_convertible>::value, + "std::is_convertible>"); +static_assert(std::is_convertible>::value, + "std::is_convertible>"); + +static_assert(std::is_convertible>::value, + "std::is_convertible>"); + +static_assert(std::is_convertible&, gsl::span>::value, + "std::is_convertible&, gsl::span>"); +static_assert(std::is_convertible&, gsl::span>::value, + "std::is_convertible&, gsl::span>"); + +static_assert(std::is_convertible&, gsl::span>::value, + "std::is_convertible&, gsl::span>"); +static_assert(std::is_convertible&, gsl::span>::value, + "std::is_convertible&, gsl::span>"); +static_assert(std::is_convertible&, gsl::span>::value, + "std::is_convertible&, gsl::span>"); +static_assert(std::is_convertible&, gsl::span>::value, + "std::is_convertible&, gsl::span>"); +static_assert(std::is_convertible&, gsl::span>::value, + "std::is_convertible&, gsl::span>"); +static_assert(std::is_convertible&, gsl::span>::value, + "std::is_convertible&, gsl::span>"); + +static_assert(std::is_convertible&, gsl::span>::value, + "std::is_convertible&, gsl::span>"); + +static_assert(std::is_convertible&, gsl::span>::value, + "std::is_convertible&, gsl::span>"); +static_assert(std::is_convertible&, gsl::span>::value, + "std::is_convertible&, gsl::span>"); +static_assert(std::is_convertible&, gsl::span>::value, + "std::is_convertible&, gsl::span>"); + +static_assert(std::is_convertible&, gsl::span>::value, + "std::is_convertible&, gsl::span>"); +static_assert(std::is_convertible&, gsl::span>::value, + "std::is_convertible&, gsl::span>"); +static_assert(std::is_convertible&, gsl::span>::value, + "std::is_convertible&, gsl::span>"); + +static_assert(std::is_convertible&, gsl::span>::value, + "std::is_convertible&, gsl::span>"); + + +#if __cplusplus >= 201703l +template +static constexpr bool AsWritableBytesCompilesFor = false; + +template +static constexpr bool AsWritableBytesCompilesFor()))>> = + true; + +static_assert(AsWritableBytesCompilesFor>, + "AsWritableBytesCompilesFor>"); +static_assert(AsWritableBytesCompilesFor>, + "AsWritableBytesCompilesFor>"); +static_assert(!AsWritableBytesCompilesFor>, + "!AsWritableBytesCompilesFor>"); +static_assert(!AsWritableBytesCompilesFor>, + "!AsWritableBytesCompilesFor>"); +#endif // __cplusplus >= 201703l diff --git a/tests/span_tests.cpp b/tests/span_tests.cpp index c41e013..2c4a19c 100644 --- a/tests/span_tests.cpp +++ b/tests/span_tests.cpp @@ -25,15 +25,11 @@ #include // for reverse_iterator, operator-, operator== #include // for unique_ptr, shared_ptr, make_unique, allo... #include // for match_results, sub_match, match_results<>... -#include // for ptrdiff_t +#include // for ptrdiff_t #include // for string #include // for integral_constant<>::value, is_default_co... #include // for vector - -namespace gsl -{ -struct fail_fast; -} // namespace gsl +#include using namespace std; using namespace gsl; @@ -110,17 +106,17 @@ TEST(span_test, from_nullptr_size_constructor) std::abort(); }); { - span s{nullptr, narrow_cast::index_type>(0)}; + span s{nullptr, narrow_cast::size_type>(0)}; EXPECT_TRUE(s.size() == 0); EXPECT_TRUE(s.data() == nullptr); - span cs{nullptr, narrow_cast::index_type>(0)}; + span cs{nullptr, narrow_cast::size_type>(0)}; EXPECT_TRUE(cs.size() == 0); EXPECT_TRUE(cs.data() == nullptr); } { auto workaround_macro = []() { - const span s{nullptr, narrow_cast::index_type>(0)}; + const span s{nullptr, narrow_cast::size_type>(0)}; }; EXPECT_DEATH(workaround_macro(), deathstring); } @@ -139,11 +135,11 @@ TEST(span_test, from_nullptr_size_constructor) EXPECT_DEATH(const_workaround_macro(), deathstring); } { - span s{nullptr, narrow_cast::index_type>(0)}; + span s{nullptr, narrow_cast::size_type>(0)}; EXPECT_TRUE(s.size() == 0); EXPECT_TRUE(s.data() == nullptr); - span cs{nullptr, narrow_cast::index_type>(0)}; + span cs{nullptr, narrow_cast::size_type>(0)}; EXPECT_TRUE(cs.size() == 0); EXPECT_TRUE(cs.data() == nullptr); } @@ -161,29 +157,21 @@ TEST(span_test, from_pointer_length_constructor) for (int i = 0; i < 4; ++i) { { - span s = {&arr[0], i}; - EXPECT_TRUE(s.size() == i); + span s = {&arr[0], narrow_cast(i)}; + EXPECT_TRUE(s.size() == narrow_cast(i)); EXPECT_TRUE(s.data() == &arr[0]); EXPECT_TRUE(s.empty() == (i == 0)); for (int j = 0; j < i; ++j) - { - EXPECT_TRUE(arr[j] == s[j]); - EXPECT_TRUE(arr[j] == s.at(j)); - EXPECT_TRUE(arr[j] == s(j)); - } + EXPECT_TRUE(arr[j] == s[narrow_cast(j)]); } { - span s = {&arr[i], 4 - narrow_cast(i)}; - EXPECT_TRUE(s.size() == 4 - i); + span s = {&arr[i], 4 - narrow_cast(i)}; + EXPECT_TRUE(s.size() == 4 - narrow_cast(i)); EXPECT_TRUE(s.data() == &arr[i]); EXPECT_TRUE(s.empty() == ((4 - i) == 0)); for (int j = 0; j < 4 - i; ++j) - { - EXPECT_TRUE(arr[j + i] == s[j]); - EXPECT_TRUE(arr[j + i] == s.at(j)); - EXPECT_TRUE(arr[j + i] == s(j)); - } + EXPECT_TRUE(arr[j + i] == s[narrow_cast(j)]); } } } @@ -198,7 +186,7 @@ TEST(span_test, from_pointer_length_constructor) { int* p = nullptr; - span s{p, narrow_cast::index_type>(0)}; + span s{p, narrow_cast::size_type>(0)}; EXPECT_TRUE(s.size() == 0); EXPECT_TRUE(s.data() == nullptr); } @@ -219,7 +207,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); } @@ -457,21 +445,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 +474,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 +520,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 +549,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 +563,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 +594,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 +605,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 +639,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 +651,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 +665,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 +678,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 +733,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()); } } @@ -966,7 +954,7 @@ TEST(span_test, from_array_constructor) EXPECT_TRUE(av.subspan(5).size() == 0); EXPECT_DEATH(av.subspan(6).size(), deathstring); const auto av2 = av.subspan(1); - for (int i = 0; i < 4; ++i) EXPECT_TRUE(av2[i] == i + 2); + for (std::size_t i = 0; i < 4; ++i) EXPECT_TRUE(av2[i] == static_cast(i) + 2); } { @@ -977,53 +965,7 @@ TEST(span_test, from_array_constructor) EXPECT_TRUE(av.subspan(5).size() == 0); EXPECT_DEATH(av.subspan(6).size(), deathstring); const auto av2 = av.subspan(1); - for (int i = 0; i < 4; ++i) EXPECT_TRUE(av2[i] == i + 2); - } - } - - TEST(span_test, at_call) - { - std::set_terminate([] { - std::cerr << "Expected Death. at_call"; - std::abort(); - }); - int arr[4] = {1, 2, 3, 4}; - - { - span s = arr; - EXPECT_TRUE(s.at(0) == 1); - EXPECT_DEATH(s.at(5), deathstring); - } - - { - int arr2d[2] = {1, 6}; - span s = arr2d; - EXPECT_TRUE(s.at(0) == 1); - EXPECT_TRUE(s.at(1) == 6); - EXPECT_DEATH(s.at(2), deathstring); - } - } - - TEST(span_test, operator_function_call) - { - std::set_terminate([] { - std::cerr << "Expected Death. operator_function_call"; - std::abort(); - }); - int arr[4] = {1, 2, 3, 4}; - - { - span s = arr; - EXPECT_TRUE(s(0) == 1); - EXPECT_DEATH(s(5), deathstring); - } - - { - int arr2d[2] = {1, 6}; - span s = arr2d; - EXPECT_TRUE(s(0) == 1); - EXPECT_TRUE(s(1) == 6); - EXPECT_DEATH(s(2), deathstring); + for (std::size_t i = 0; i < 4; ++i) EXPECT_TRUE(av2[i] == static_cast(i) + 2); } } @@ -1067,28 +1009,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.begin() == std::begin(s)); + EXPECT_TRUE(s.end() == std::end(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)); - + EXPECT_TRUE(s.crbegin() == crbegin(s)); EXPECT_TRUE(s.crend() == crend(s)); } @@ -1097,9 +1039,9 @@ 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) @@ -1149,6 +1091,28 @@ TEST(span_test, from_array_constructor) } } + TEST(span_test, incomparable_iterators) + { + std::set_terminate([] { + std::cerr << "Expected Death. incomparable_iterators"; + std::abort(); + }); + + int a[] = {1, 2, 3, 4}; + int b[] = {1, 2, 3, 4}; + { + span s = a; + span s2 = b; +#if (__cplusplus > 201402L) + EXPECT_DEATH([[maybe_unused]] bool _ = (s.begin() == s2.begin()), deathstring); + EXPECT_DEATH([[maybe_unused]] bool _ = (s.begin() <= s2.begin()), deathstring); +#else + EXPECT_DEATH(bool _ = (s.begin() == s2.begin()), deathstring); + EXPECT_DEATH(bool _ = (s.begin() <= s2.begin()), deathstring); +#endif + } + } + TEST(span_test, begin_end) { std::set_terminate([] { @@ -1484,8 +1448,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); @@ -1510,9 +1478,15 @@ TEST(span_test, from_array_constructor) EXPECT_TRUE(static_cast(bs.data()) == static_cast(s.data())); EXPECT_TRUE(bs.size() == s.size_bytes()); } + + int b[5] = {1, 2, 3, 4, 5}; + { + span sp(begin(b), static_cast(-2)); + EXPECT_DEATH((void) sp.size_bytes(), deathstring); + } } - TEST(span_test, as_writeable_bytes) + TEST(span_test, as_writable_bytes) { int a[] = {1, 2, 3, 4}; @@ -1521,7 +1495,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 @@ -1529,7 +1503,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); @@ -1539,7 +1513,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()); } @@ -1577,12 +1551,16 @@ TEST(span_test, from_array_constructor) // even when done dynamically { + /* + // this now results in a compile-time error, rather than runtime. + // There is no suitable conversion from dynamic span to fixed span. span s = arr; auto f = [&]() { const span s2 = s; static_cast(s2); }; EXPECT_DEATH(f(), deathstring); + */ } // but doing so explicitly is ok @@ -1597,12 +1575,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}; @@ -1624,12 +1609,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) diff --git a/tests/string_span_tests.cpp b/tests/string_span_tests.cpp index e501bba..7a9f7fb 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'; @@ -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)); } @@ -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()); } diff --git a/tests/utils_tests.cpp b/tests/utils_tests.cpp index b6b5fc9..f7f7ce3 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::ptrdiff_t using namespace gsl;