mirror of
https://github.com/microsoft/GSL.git
synced 2024-11-03 17:56:43 -05:00
almost parity with std::span
This commit is contained in:
parent
a49ff1b8df
commit
377b2db537
107
include/gsl/span
107
include/gsl/span
@ -111,8 +111,7 @@ namespace details
|
|||||||
|
|
||||||
template <std::size_t From, std::size_t To>
|
template <std::size_t From, std::size_t To>
|
||||||
struct is_allowed_extent_conversion
|
struct is_allowed_extent_conversion
|
||||||
: public std::integral_constant<bool, From == To || From == gsl::dynamic_extent ||
|
: public std::integral_constant<bool, From == To || To == gsl::dynamic_extent>
|
||||||
To == gsl::dynamic_extent>
|
|
||||||
{
|
{
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -301,7 +300,9 @@ namespace details
|
|||||||
if (n < 0) Expects(current_ - begin_ >= -n);
|
if (n < 0) Expects(current_ - begin_ >= -n);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
|
GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
|
||||||
|
// clang-format on
|
||||||
constexpr pointer _Unwrapped() const noexcept
|
constexpr pointer _Unwrapped() const noexcept
|
||||||
{ // after seeking *this to a high water mark, or using one of the
|
{ // after seeking *this to a high water mark, or using one of the
|
||||||
// _Verify_xxx functions above, unwrap this span_iterator to a raw
|
// _Verify_xxx functions above, unwrap this span_iterator to a raw
|
||||||
@ -316,7 +317,9 @@ namespace details
|
|||||||
#else
|
#else
|
||||||
static constexpr bool _Unwrap_when_unverified = false;
|
static constexpr bool _Unwrap_when_unverified = false;
|
||||||
#endif
|
#endif
|
||||||
|
// clang-format off
|
||||||
GSL_SUPPRESS(con.3) // NO-FORMAT: attribute // TODO: false positive
|
GSL_SUPPRESS(con.3) // NO-FORMAT: attribute // TODO: false positive
|
||||||
|
// clang-format on
|
||||||
constexpr void _Seek_to(const pointer p) noexcept
|
constexpr void _Seek_to(const pointer p) noexcept
|
||||||
{ // adjust the position of *this to previously verified location p
|
{ // adjust the position of *this to previously verified location p
|
||||||
// after _Unwrapped
|
// after _Unwrapped
|
||||||
@ -392,7 +395,9 @@ public:
|
|||||||
using value_type = std::remove_cv_t<ElementType>;
|
using value_type = std::remove_cv_t<ElementType>;
|
||||||
using size_type = std::size_t;
|
using size_type = std::size_t;
|
||||||
using pointer = element_type*;
|
using pointer = element_type*;
|
||||||
|
using const_pointer = const element_type*;
|
||||||
using reference = element_type&;
|
using reference = element_type&;
|
||||||
|
using const_reference = const element_type&;
|
||||||
using difference_type = std::ptrdiff_t;
|
using difference_type = std::ptrdiff_t;
|
||||||
|
|
||||||
using iterator = details::span_iterator<ElementType>;
|
using iterator = details::span_iterator<ElementType>;
|
||||||
@ -410,38 +415,48 @@ public:
|
|||||||
|
|
||||||
// [span.cons], span constructors, copy, assignment, and destructor
|
// [span.cons], span constructors, copy, assignment, and destructor
|
||||||
template <bool Dependent = false,
|
template <bool Dependent = false,
|
||||||
// "Dependent" is needed to make "std::enable_if_t<Dependent || Extent == 0 || Extent == dynamic_extent>" SFINAE,
|
// "Dependent" is needed to make "std::enable_if_t<Dependent || Extent == 0 || Extent
|
||||||
// since "std::enable_if_t<Extent == 0 || Extent == dynamic_extent>" is ill-formed when Extent is greater than 0.
|
// == dynamic_extent>" SFINAE, since "std::enable_if_t<Extent == 0 || Extent ==
|
||||||
|
// dynamic_extent>" is ill-formed when Extent is greater than 0.
|
||||||
class = std::enable_if_t<(Dependent || Extent == 0 || Extent == dynamic_extent)>>
|
class = std::enable_if_t<(Dependent || Extent == 0 || Extent == dynamic_extent)>>
|
||||||
constexpr span() noexcept : storage_(nullptr, details::extent_type<0>())
|
constexpr span() noexcept : storage_(nullptr, details::extent_type<0>())
|
||||||
{}
|
{}
|
||||||
|
|
||||||
constexpr span(pointer ptr, size_type count) noexcept : storage_(ptr, count) {}
|
constexpr span(pointer ptr, size_type count) noexcept : storage_(ptr, count)
|
||||||
|
{
|
||||||
|
if (Extent != dynamic_extent) Expects(count == Extent);
|
||||||
|
}
|
||||||
|
|
||||||
constexpr span(pointer firstElem, pointer lastElem) noexcept
|
constexpr span(pointer firstElem, pointer lastElem) noexcept
|
||||||
: storage_(firstElem, static_cast<std::size_t>(std::distance(firstElem, lastElem)))
|
: storage_(firstElem, static_cast<std::size_t>(std::distance(firstElem, lastElem)))
|
||||||
{}
|
{
|
||||||
|
if (Extent != dynamic_extent) { Expects(lastElem - firstElem == Extent); }
|
||||||
|
}
|
||||||
|
|
||||||
template <std::size_t N>
|
template <std::size_t N>
|
||||||
constexpr span(element_type (&arr)[N]) noexcept
|
constexpr span(element_type (&arr)[N]) noexcept
|
||||||
: storage_(KnownNotNull{std::addressof(arr[0])}, details::extent_type<N>())
|
: storage_(KnownNotNull{std::addressof(arr[0])}, details::extent_type<N>())
|
||||||
{}
|
{}
|
||||||
|
|
||||||
template <std::size_t N, class = std::enable_if_t<(N > 0)>>
|
template <std::size_t N, std::size_t Ext = Extent,
|
||||||
constexpr span(std::array<std::remove_const_t<element_type>, N>& arr) noexcept
|
std::enable_if_t<(N == Ext || Ext == dynamic_extent), int> = 0>
|
||||||
|
constexpr span(std::array<value_type, N>& arr) noexcept
|
||||||
: storage_(KnownNotNull{arr.data()}, details::extent_type<N>())
|
: storage_(KnownNotNull{arr.data()}, details::extent_type<N>())
|
||||||
{}
|
{}
|
||||||
|
|
||||||
constexpr span(std::array<std::remove_const_t<element_type>, 0>&) noexcept
|
template <std::size_t N, std::size_t Ext = Extent,
|
||||||
|
std::enable_if_t<((N == Ext || Ext == dynamic_extent) &&
|
||||||
|
std::is_convertible<const value_type*, element_type*>::value),
|
||||||
|
int> = 0>
|
||||||
|
constexpr span(const std::array<value_type, N>& arr) noexcept
|
||||||
|
: storage_(KnownNotNull{arr.data()}, details::extent_type<N>())
|
||||||
|
{}
|
||||||
|
|
||||||
|
constexpr span(std::array<value_type, 0>&) noexcept
|
||||||
: storage_(static_cast<pointer>(nullptr), details::extent_type<0>())
|
: storage_(static_cast<pointer>(nullptr), details::extent_type<0>())
|
||||||
{}
|
{}
|
||||||
|
|
||||||
template <std::size_t N, class = std::enable_if_t<(N > 0)>>
|
constexpr span(const std::array<value_type, 0>&) noexcept
|
||||||
constexpr span(const std::array<std::remove_const_t<element_type>, N>& arr) noexcept
|
|
||||||
: storage_(KnownNotNull{arr.data()}, details::extent_type<N>())
|
|
||||||
{}
|
|
||||||
|
|
||||||
constexpr span(const std::array<std::remove_const_t<element_type>, 0>&) noexcept
|
|
||||||
: storage_(static_cast<pointer>(nullptr), details::extent_type<0>())
|
: storage_(static_cast<pointer>(nullptr), details::extent_type<0>())
|
||||||
{}
|
{}
|
||||||
|
|
||||||
@ -451,8 +466,8 @@ public:
|
|||||||
class = std::enable_if_t<
|
class = std::enable_if_t<
|
||||||
!details::is_span<Container>::value && !details::is_std_array<Container>::value &&
|
!details::is_span<Container>::value && !details::is_std_array<Container>::value &&
|
||||||
std::is_convertible<typename Container::pointer, pointer>::value &&
|
std::is_convertible<typename Container::pointer, pointer>::value &&
|
||||||
std::is_convertible<typename Container::pointer,
|
std::is_convertible<pointer, typename Container::pointer>::value &&
|
||||||
decltype(std::declval<Container>().data())>::value>>
|
std::is_convertible<decltype(std::declval<Container&>().data()), pointer>::value>>
|
||||||
constexpr span(Container& cont) noexcept : span(cont.data(), cont.size())
|
constexpr span(Container& cont) noexcept : span(cont.data(), cont.size())
|
||||||
{}
|
{}
|
||||||
|
|
||||||
@ -460,10 +475,8 @@ public:
|
|||||||
class = std::enable_if_t<
|
class = std::enable_if_t<
|
||||||
std::is_const<element_type>::value && !details::is_span<Container>::value &&
|
std::is_const<element_type>::value && !details::is_span<Container>::value &&
|
||||||
std::is_convertible<typename Container::pointer, pointer>::value &&
|
std::is_convertible<typename Container::pointer, pointer>::value &&
|
||||||
std::is_convertible<typename Container::pointer,
|
std::is_convertible<decltype(std::declval<Container&>().data()), pointer>::value>>
|
||||||
decltype(std::declval<Container>().data())>::value>>
|
constexpr span(const Container& cont) noexcept : span(cont.data(), cont.size())
|
||||||
constexpr span(const Container& cont) noexcept
|
|
||||||
: span(cont.data(), cont.size())
|
|
||||||
{}
|
{}
|
||||||
|
|
||||||
constexpr span(const span& other) noexcept = default;
|
constexpr span(const span& other) noexcept = default;
|
||||||
@ -489,16 +502,20 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <std::size_t Count>
|
template <std::size_t Count>
|
||||||
|
// clang-format off
|
||||||
GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
|
GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
|
||||||
constexpr span<element_type, Count> last() const noexcept
|
// clang-format on
|
||||||
|
constexpr span<element_type, Count> last() const noexcept
|
||||||
{
|
{
|
||||||
Expects(size() >= Count);
|
Expects(size() >= Count);
|
||||||
return {data() + (size() - Count), Count};
|
return {data() + (size() - Count), Count};
|
||||||
}
|
}
|
||||||
|
|
||||||
template <std::size_t Offset, std::size_t Count = dynamic_extent>
|
template <std::size_t Offset, std::size_t Count = dynamic_extent>
|
||||||
|
// clang-format off
|
||||||
GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
|
GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
|
||||||
constexpr auto subspan() const noexcept ->
|
// clang-format on
|
||||||
|
constexpr auto subspan() const noexcept ->
|
||||||
typename details::calculate_subspan_type<ElementType, Extent, Offset, Count>::type
|
typename details::calculate_subspan_type<ElementType, Extent, Offset, Count>::type
|
||||||
{
|
{
|
||||||
Expects((size() >= Offset) && (Count == dynamic_extent || (Count <= size() - Offset)));
|
Expects((size() >= Offset) && (Count == dynamic_extent || (Count <= size() - Offset)));
|
||||||
@ -537,7 +554,9 @@ public:
|
|||||||
constexpr bool empty() const noexcept { return size() == 0; }
|
constexpr bool empty() const noexcept { return size() == 0; }
|
||||||
|
|
||||||
// [span.elem], span element access
|
// [span.elem], span element access
|
||||||
|
// clang-format off
|
||||||
GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
|
GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
|
||||||
|
// clang-format on
|
||||||
constexpr reference operator[](size_type idx) const noexcept
|
constexpr reference operator[](size_type idx) const noexcept
|
||||||
{
|
{
|
||||||
Expects(idx < size());
|
Expects(idx < size());
|
||||||
@ -602,7 +621,9 @@ public:
|
|||||||
constexpr pointer _Unchecked_begin() const noexcept { return data(); }
|
constexpr pointer _Unchecked_begin() const noexcept { return data(); }
|
||||||
constexpr pointer _Unchecked_end() const noexcept
|
constexpr pointer _Unchecked_end() const noexcept
|
||||||
{
|
{
|
||||||
|
// clang-format off
|
||||||
GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
|
GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
|
||||||
|
// clang-format on
|
||||||
return data() + size();
|
return data() + size();
|
||||||
}
|
}
|
||||||
#endif // _MSC_VER
|
#endif // _MSC_VER
|
||||||
@ -662,7 +683,9 @@ private:
|
|||||||
return tmp.subspan(offset, count);
|
return tmp.subspan(offset, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
|
GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
|
||||||
|
// clang-format on
|
||||||
span<element_type, dynamic_extent> make_subspan(size_type offset, size_type count,
|
span<element_type, dynamic_extent> make_subspan(size_type offset, size_type count,
|
||||||
subspan_selector<dynamic_extent>) const
|
subspan_selector<dynamic_extent>) const
|
||||||
{
|
{
|
||||||
@ -675,6 +698,20 @@ private:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if (defined(__cpp_deduction_guides) && (__cpp_deduction_guides >= 201611L))
|
||||||
|
|
||||||
|
// Deduction Guides
|
||||||
|
template <class Type, std::size_t Extent>
|
||||||
|
span(Type (&)[Extent])->span<Type, Extent>;
|
||||||
|
|
||||||
|
template <class Type, std::size_t Size>
|
||||||
|
span(std::array<Type, Size>&)->span<Type, Size>;
|
||||||
|
|
||||||
|
template <class Type, std::size_t Size>
|
||||||
|
span(const std::array<Type, Size>&)->span<const Type, Size>;
|
||||||
|
|
||||||
|
#endif // ( defined(__cpp_deduction_guides) && (__cpp_deduction_guides >= 201611L) )
|
||||||
|
|
||||||
#if defined(GSL_USE_STATIC_CONSTEXPR_WORKAROUND)
|
#if defined(GSL_USE_STATIC_CONSTEXPR_WORKAROUND)
|
||||||
template <class ElementType, std::size_t Extent>
|
template <class ElementType, std::size_t Extent>
|
||||||
constexpr const typename span<ElementType, Extent>::size_type span<ElementType, Extent>::extent;
|
constexpr const typename span<ElementType, Extent>::size_type span<ElementType, Extent>::extent;
|
||||||
@ -742,16 +779,32 @@ template <class ElementType, std::size_t Extent>
|
|||||||
span<const byte, details::calculate_byte_size<ElementType, Extent>::value>
|
span<const byte, details::calculate_byte_size<ElementType, Extent>::value>
|
||||||
as_bytes(span<ElementType, Extent> s) noexcept
|
as_bytes(span<ElementType, Extent> s) noexcept
|
||||||
{
|
{
|
||||||
|
// clang-format off
|
||||||
GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
|
GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
|
||||||
|
// clang-format on
|
||||||
return {reinterpret_cast<const byte*>(s.data()), s.size_bytes()};
|
return {reinterpret_cast<const byte*>(s.data()), s.size_bytes()};
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class ElementType, std::size_t Extent,
|
template <class ElementType, std::size_t Extent,
|
||||||
class = std::enable_if_t<!std::is_const<ElementType>::value>>
|
std::enable_if_t<!std::is_const<ElementType>::value, int> = 0>
|
||||||
span<byte, details::calculate_byte_size<ElementType, Extent>::value>
|
span<byte, details::calculate_byte_size<ElementType, Extent>::value>
|
||||||
|
as_writable_bytes(span<ElementType, Extent> s) noexcept
|
||||||
|
{
|
||||||
|
// clang-format off
|
||||||
|
GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
|
||||||
|
// clang-format on
|
||||||
|
return {reinterpret_cast<byte*>(s.data()), s.size_bytes()};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class ElementType, std::size_t Extent,
|
||||||
|
std::enable_if_t<!std::is_const<ElementType>::value, int> = 0>
|
||||||
|
[[deprecated(
|
||||||
|
"use as_writable_bytes")]] span<byte, details::calculate_byte_size<ElementType, Extent>::value>
|
||||||
as_writeable_bytes(span<ElementType, Extent> s) noexcept
|
as_writeable_bytes(span<ElementType, Extent> s) noexcept
|
||||||
{
|
{
|
||||||
|
// clang-format off
|
||||||
GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
|
GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
|
||||||
|
// clang-format on
|
||||||
return {reinterpret_cast<byte*>(s.data()), s.size_bytes()};
|
return {reinterpret_cast<byte*>(s.data()), s.size_bytes()};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -759,8 +812,7 @@ as_writeable_bytes(span<ElementType, Extent> s) noexcept
|
|||||||
// make_span() - Utility functions for creating spans
|
// make_span() - Utility functions for creating spans
|
||||||
//
|
//
|
||||||
template <class ElementType>
|
template <class ElementType>
|
||||||
constexpr span<ElementType> make_span(ElementType* ptr,
|
constexpr span<ElementType> make_span(ElementType* ptr, typename span<ElementType>::size_type count)
|
||||||
typename span<ElementType>::size_type count)
|
|
||||||
{
|
{
|
||||||
return span<ElementType>(ptr, count);
|
return span<ElementType>(ptr, count);
|
||||||
}
|
}
|
||||||
@ -812,8 +864,7 @@ constexpr ElementType& at(span<ElementType, Extent> s, index i)
|
|||||||
|
|
||||||
// [span.obs] Free observer functions
|
// [span.obs] Free observer functions
|
||||||
template <class ElementType, std::size_t Extent>
|
template <class ElementType, std::size_t Extent>
|
||||||
constexpr std::ptrdiff_t
|
constexpr std::ptrdiff_t ssize(const span<ElementType, Extent>& s) noexcept
|
||||||
ssize(const span<ElementType, Extent>& s) noexcept
|
|
||||||
{
|
{
|
||||||
return static_cast<std::ptrdiff_t>(s.size());
|
return static_cast<std::ptrdiff_t>(s.size());
|
||||||
}
|
}
|
||||||
|
@ -1551,11 +1551,15 @@ TEST(span_test, from_array_constructor)
|
|||||||
// even when done dynamically
|
// even when done dynamically
|
||||||
{
|
{
|
||||||
span<int> s = arr;
|
span<int> s = arr;
|
||||||
|
/*
|
||||||
|
// this now results in a compile-time error, rather than runtime.
|
||||||
|
// There is no suitable conversion from dynamic span to fixed span.
|
||||||
auto f = [&]() {
|
auto f = [&]() {
|
||||||
const span<int, 2> s2 = s;
|
const span<int, 2> s2 = s;
|
||||||
static_cast<void>(s2);
|
static_cast<void>(s2);
|
||||||
};
|
};
|
||||||
EXPECT_DEATH(f(), deathstring);
|
EXPECT_DEATH(f(), deathstring);
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
// but doing so explicitly is ok
|
// but doing so explicitly is ok
|
||||||
@ -1570,12 +1574,19 @@ TEST(span_test, from_array_constructor)
|
|||||||
static_cast<void>(s1);
|
static_cast<void>(s1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ...or dynamically
|
/*
|
||||||
|
// this is not a legal operation in std::span, so we are no longer supporting it
|
||||||
|
// conversion from span<int, 4> to span<int, dynamic_extent> via call to `first`
|
||||||
|
// then convert from span<int, dynamic_extent> to span<int, 1>
|
||||||
|
// The dynamic to fixed extents are not supported in the standard
|
||||||
|
// to make this work, span<int, 1> would need to be span<int>.
|
||||||
{
|
{
|
||||||
|
|
||||||
// NB: implicit conversion to span<int,1> from span<int>
|
// NB: implicit conversion to span<int,1> from span<int>
|
||||||
span<int, 1> s1 = s4.first(1);
|
span<int, 1> s1 = s4.first(1);
|
||||||
static_cast<void>(s1);
|
static_cast<void>(s1);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
// initialization or assignment to static span that requires size INCREASE is not ok.
|
// initialization or assignment to static span that requires size INCREASE is not ok.
|
||||||
int arr2[2] = {1, 2};
|
int arr2[2] = {1, 2};
|
||||||
@ -1597,12 +1608,15 @@ TEST(span_test, from_array_constructor)
|
|||||||
EXPECT_DEATH(f(), deathstring);
|
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
|
// this should fail - we are trying to assign a small dynamic span to a fixed_size larger one
|
||||||
span<int> av = arr2; auto f = [&]() {
|
span<int> av = arr2; auto f = [&]() {
|
||||||
const span<int, 4> _s4 = av;
|
const span<int, 4> _s4 = av;
|
||||||
static_cast<void>(_s4);
|
static_cast<void>(_s4);
|
||||||
};
|
};
|
||||||
EXPECT_DEATH(f(), deathstring);
|
EXPECT_DEATH(f(), deathstring);
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(span_test, interop_with_std_regex)
|
TEST(span_test, interop_with_std_regex)
|
||||||
|
Loading…
Reference in New Issue
Block a user