Merge pull request #887 from JordanMaples/dev/jomaples/p1976r2

gsl::span P1976R2 implemenation
This commit is contained in:
Jordan Maples [MSFT] 2020-05-21 10:07:37 -07:00 committed by GitHub
commit 8cd19412b4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 93 additions and 43 deletions

View File

@ -343,15 +343,9 @@ namespace details
constexpr extent_type() noexcept = default; constexpr extent_type() noexcept = default;
template <size_type Other> constexpr explicit extent_type(extent_type<dynamic_extent>);
constexpr extent_type(extent_type<Other> ext)
{
static_assert(Other == Ext,
"Mismatch between fixed-size extent and size of initializing data.");
Expects(ext.size() == Ext);
}
constexpr extent_type(size_type size) { Expects(size == Ext); } constexpr explicit extent_type(size_type size) { Expects(size == Ext); }
constexpr size_type size() const noexcept { return Ext; } constexpr size_type size() const noexcept { return Ext; }
}; };
@ -363,10 +357,10 @@ namespace details
using size_type = std::size_t; using size_type = std::size_t;
template <size_type Other> template <size_type Other>
explicit constexpr extent_type(extent_type<Other> ext) : size_(ext.size()) constexpr explicit extent_type(extent_type<Other> ext) : size_(ext.size())
{} {}
explicit constexpr extent_type(size_type size) : size_(size) constexpr explicit extent_type(size_type size) : size_(size)
{ {
Expects(size != dynamic_extent); Expects(size != dynamic_extent);
} }
@ -377,6 +371,12 @@ namespace details
size_type size_; size_type size_;
}; };
template <std::size_t Ext>
constexpr extent_type<Ext>::extent_type(extent_type<dynamic_extent> ext)
{
Expects(ext.size() == Ext);
}
template <class ElementType, std::size_t Extent, std::size_t Offset, std::size_t Count> template <class ElementType, std::size_t Extent, std::size_t Offset, std::size_t Count>
struct calculate_subspan_type struct calculate_subspan_type
{ {
@ -420,18 +420,28 @@ public:
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) template <std::size_t MyExtent = Extent, std::enable_if_t<MyExtent != gsl::dynamic_extent, int> = 0>
constexpr explicit span(pointer ptr, size_type count) noexcept : storage_(ptr, count)
{ {
if (Extent != dynamic_extent) Expects(count == Extent); Expects(count == Extent);
} }
constexpr span(pointer firstElem, pointer lastElem) noexcept template <std::size_t MyExtent = Extent, std::enable_if_t<MyExtent == gsl::dynamic_extent, int> = 0>
constexpr span(pointer ptr, size_type count) noexcept : storage_(ptr, count)
{}
template <std::size_t MyExtent = Extent, std::enable_if_t<MyExtent != gsl::dynamic_extent, int> = 0>
constexpr explicit span(pointer firstElem, pointer lastElem) noexcept
: storage_(firstElem, static_cast<std::size_t>(lastElem - firstElem)) : storage_(firstElem, static_cast<std::size_t>(lastElem - firstElem))
{ {
if (Extent != dynamic_extent) Expects(lastElem - firstElem == static_cast<difference_type>(Extent));
{ Expects(lastElem - firstElem == static_cast<difference_type>(Extent)); }
} }
template <std::size_t MyExtent = Extent, std::enable_if_t<MyExtent == gsl::dynamic_extent, int> = 0>
constexpr span(pointer firstElem, pointer lastElem) noexcept
: storage_(firstElem, static_cast<std::size_t>(lastElem - firstElem))
{}
template <std::size_t N, template <std::size_t N,
std::enable_if_t<details::is_allowed_extent_conversion<N, Extent>::value, int> = 0> std::enable_if_t<details::is_allowed_extent_conversion<N, Extent>::value, int> = 0>
constexpr span(element_type (&arr)[N]) noexcept constexpr span(element_type (&arr)[N]) noexcept
@ -456,40 +466,74 @@ public:
: storage_(KnownNotNull{arr.data()}, details::extent_type<N>()) : storage_(KnownNotNull{arr.data()}, details::extent_type<N>())
{} {}
// NB: the SFINAE here uses .data() as an incomplete/imperfect proxy for the requirement // NB: the SFINAE on these constructors uses .data() as an incomplete/imperfect proxy for the
// on Container to be a contiguous sequence container. // requirement on Container to be a contiguous sequence container.
template <class Container, template <std::size_t MyExtent = Extent, class Container,
class = std::enable_if_t< std::enable_if_t<
MyExtent != dynamic_extent &&
!details::is_span<Container>::value && !details::is_std_array<Container>::value && !details::is_span<Container>::value && !details::is_std_array<Container>::value &&
std::is_pointer<decltype(std::declval<Container&>().data())>::value && std::is_pointer<decltype(std::declval<Container&>().data())>::value &&
std::is_convertible< std::is_convertible<
std::remove_pointer_t<decltype(std::declval<Container&>().data())> (*)[], std::remove_pointer_t<decltype(std::declval<Container&>().data())> (*)[],
element_type (*)[]>::value>> element_type (*)[]>::value, int> = 0>
constexpr explicit span(Container& cont) noexcept : span(cont.data(), cont.size())
{}
template <std::size_t MyExtent = Extent, class Container,
std::enable_if_t<
MyExtent == dynamic_extent &&
!details::is_span<Container>::value && !details::is_std_array<Container>::value &&
std::is_pointer<decltype(std::declval<Container&>().data())>::value &&
std::is_convertible<
std::remove_pointer_t<decltype(std::declval<Container&>().data())> (*)[],
element_type (*)[]>::value, int> = 0>
constexpr span(Container& cont) noexcept : span(cont.data(), cont.size()) constexpr span(Container& cont) noexcept : span(cont.data(), cont.size())
{} {}
template <class Container, template <std::size_t MyExtent = Extent, class Container,
class = std::enable_if_t< std::enable_if_t<
MyExtent != dynamic_extent &&
std::is_const<element_type>::value && !details::is_span<Container>::value && std::is_const<element_type>::value && !details::is_span<Container>::value &&
!details::is_std_array<Container>::value && !details::is_std_array<Container>::value &&
std::is_pointer<decltype(std::declval<const Container&>().data())>::value && std::is_pointer<decltype(std::declval<const Container&>().data())>::value &&
std::is_convertible<std::remove_pointer_t< std::is_convertible<std::remove_pointer_t<
decltype(std::declval<const Container&>().data())> (*)[], decltype(std::declval<const Container&>().data())> (*)[],
element_type (*)[]>::value>> element_type (*)[]>::value, int> = 0>
constexpr explicit span(const Container& cont) noexcept : span(cont.data(), cont.size())
{}
template <std::size_t MyExtent = Extent, class Container,
std::enable_if_t<
MyExtent == dynamic_extent &&
std::is_const<element_type>::value && !details::is_span<Container>::value &&
!details::is_std_array<Container>::value &&
std::is_pointer<decltype(std::declval<const Container&>().data())>::value &&
std::is_convertible<std::remove_pointer_t<
decltype(std::declval<const Container&>().data())> (*)[],
element_type (*)[]>::value, int> = 0>
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;
template < template <
class OtherElementType, std::size_t OtherExtent, class OtherElementType, std::size_t OtherExtent, std::size_t MyExtent = Extent,
class = std::enable_if_t< std::enable_if_t<
details::is_allowed_extent_conversion<OtherExtent, Extent>::value && (MyExtent == dynamic_extent || MyExtent == OtherExtent) &&
details::is_allowed_element_type_conversion<OtherElementType, element_type>::value>> details::is_allowed_element_type_conversion<OtherElementType, element_type>::value, int> = 0>
constexpr span(const span<OtherElementType, OtherExtent>& other) noexcept constexpr span(const span<OtherElementType, OtherExtent>& other) noexcept
: storage_(other.data(), details::extent_type<OtherExtent>(other.size())) : storage_(other.data(), details::extent_type<OtherExtent>(other.size()))
{} {}
template <
class OtherElementType, std::size_t OtherExtent, std::size_t MyExtent = Extent,
std::enable_if_t<
MyExtent != dynamic_extent && OtherExtent == dynamic_extent &&
details::is_allowed_element_type_conversion<OtherElementType, element_type>::value, int> = 0>
constexpr explicit span(const span<OtherElementType, OtherExtent>& other) noexcept
: storage_(other.data(), details::extent_type<OtherExtent>(other.size()))
{}
~span() noexcept = default; ~span() noexcept = default;
constexpr span& operator=(const span& other) noexcept = default; constexpr span& operator=(const span& other) noexcept = default;
@ -498,7 +542,7 @@ public:
constexpr span<element_type, Count> first() const noexcept constexpr span<element_type, Count> first() const noexcept
{ {
Expects(Count <= size()); Expects(Count <= size());
return {data(), Count}; return span<element_type, Count>{data(), Count};
} }
template <std::size_t Count> template <std::size_t Count>
@ -508,7 +552,7 @@ public:
constexpr span<element_type, Count> last() const noexcept constexpr span<element_type, Count> last() const noexcept
{ {
Expects(Count <= size()); Expects(Count <= size());
return {data() + (size() - Count), Count}; return span<element_type, Count>{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>
@ -519,8 +563,8 @@ public:
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)));
using type = typename details::calculate_subspan_type<ElementType, Extent, Offset, Count>::type;
return {data() + Offset, Count == dynamic_extent ? size() - Offset : Count}; return type{data() + Offset, Count == dynamic_extent ? size() - Offset : Count};
} }
constexpr span<element_type, dynamic_extent> first(size_type count) const noexcept constexpr span<element_type, dynamic_extent> first(size_type count) const noexcept
@ -728,10 +772,12 @@ 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
{ {
using type = span<const byte, details::calculate_byte_size<ElementType, Extent>::value>;
// clang-format off // clang-format off
GSL_SUPPRESS(type.1) // NO-FORMAT: attribute GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
// clang-format on // clang-format on
return {reinterpret_cast<const byte*>(s.data()), s.size_bytes()}; return type{reinterpret_cast<const byte*>(s.data()), s.size_bytes()};
} }
template <class ElementType, std::size_t Extent, template <class ElementType, std::size_t Extent,
@ -739,10 +785,12 @@ template <class ElementType, std::size_t Extent,
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 as_writable_bytes(span<ElementType, Extent> s) noexcept
{ {
using type = span<byte, details::calculate_byte_size<ElementType, Extent>::value>;
// clang-format off // clang-format off
GSL_SUPPRESS(type.1) // NO-FORMAT: attribute GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
// clang-format on // clang-format on
return {reinterpret_cast<byte*>(s.data()), s.size_bytes()}; return type{reinterpret_cast<byte*>(s.data()), s.size_bytes()};
} }
} // namespace gsl } // namespace gsl

View File

@ -308,7 +308,7 @@ public:
private: private:
static impl_type remove_z(pointer const& sz, std::size_t max) static impl_type remove_z(pointer const& sz, std::size_t max)
{ {
return {sz, details::string_length(sz, max)}; return impl_type(sz, details::string_length(sz, max));
} }
template <std::size_t N> template <std::size_t N>

View File

@ -846,8 +846,6 @@ static_assert(!std::is_constructible<gsl::span<int, 3>, std::array<int, 500>&>::
"!std::is_constructible<gsl::span<int, 3>, std::array<int, 500>&>"); "!std::is_constructible<gsl::span<int, 3>, std::array<int, 500>&>");
static_assert(!std::is_constructible<gsl::span<int, 3>, const std::array<int, 3>&>::value, static_assert(!std::is_constructible<gsl::span<int, 3>, const std::array<int, 3>&>::value,
"!std::is_constructible<gsl::span<int, 3>, const std::array<int, 3>&>"); "!std::is_constructible<gsl::span<int, 3>, const std::array<int, 3>&>");
static_assert(!std::is_constructible<gsl::span<int, 3>, const gsl::span<int>&>::value,
"!std::is_constructible<gsl::span<int, 3>, const gsl::span<int>&>");
static_assert(!std::is_constructible<gsl::span<int, 3>, const gsl::span<int, 500>&>::value, static_assert(!std::is_constructible<gsl::span<int, 3>, const gsl::span<int, 500>&>::value,
"!std::is_constructible<gsl::span<int, 3>, const gsl::span<int, 500>&>"); "!std::is_constructible<gsl::span<int, 3>, const gsl::span<int, 500>&>");
static_assert(!std::is_constructible<gsl::span<int, 3>, const gsl::span<const int>&>::value, static_assert(!std::is_constructible<gsl::span<int, 3>, const gsl::span<const int>&>::value,
@ -866,12 +864,8 @@ static_assert(!std::is_constructible<gsl::span<const int>, std::array<double, 3>
static_assert(!std::is_constructible<gsl::span<const int>, const gsl::span<double, 3>&>::value, static_assert(!std::is_constructible<gsl::span<const int>, const gsl::span<double, 3>&>::value,
"!std::is_constructible<gsl::span<const int>, const gsl::span<double, 3>&>"); "!std::is_constructible<gsl::span<const int>, const gsl::span<double, 3>&>");
static_assert(!std::is_constructible<gsl::span<const int, 3>, const gsl::span<int>&>::value,
"!std::is_constructible<gsl::span<const int, 3>, const gsl::span<int>&>");
static_assert(!std::is_constructible<gsl::span<const int, 3>, const gsl::span<int, 500>&>::value, static_assert(!std::is_constructible<gsl::span<const int, 3>, const gsl::span<int, 500>&>::value,
"!std::is_constructible<gsl::span<const int, 3>, const gsl::span<int, 500>&>"); "!std::is_constructible<gsl::span<const int, 3>, const gsl::span<int, 500>&>");
static_assert(!std::is_constructible<gsl::span<const int, 3>, const gsl::span<const int>&>::value,
"!std::is_constructible<gsl::span<const int, 3>, const gsl::span<const int>&>");
static_assert( static_assert(
!std::is_constructible<gsl::span<const int, 3>, const gsl::span<const int, 500>&>::value, !std::is_constructible<gsl::span<const int, 3>, const gsl::span<const int, 500>&>::value,
"!std::is_constructible<gsl::span<const int, 3>, const gsl::span<const int, 500>&>"); "!std::is_constructible<gsl::span<const int, 3>, const gsl::span<const int, 500>&>");
@ -925,6 +919,14 @@ static_assert(!std::is_constructible<gsl::span<const Derived>, std::array<Base,
static_assert(!std::is_constructible<gsl::span<const Derived>, const std::array<Base, 3>&>::value, static_assert(!std::is_constructible<gsl::span<const Derived>, const std::array<Base, 3>&>::value,
"!std::is_constructible<gsl::span<const Derived>, const std::array<Base, 3>&>"); "!std::is_constructible<gsl::span<const Derived>, const std::array<Base, 3>&>");
// Explicit construction enabled in P1976R2
static_assert(std::is_constructible<gsl::span<int, 3>, const gsl::span<int>&>::value,
"std::is_constructible<gsl::span<int, 3>, const gsl::span<int>&>");
static_assert(std::is_constructible<gsl::span<const int, 3>, const gsl::span<int>&>::value,
"std::is_constructible<gsl::span<const int, 3>, const gsl::span<int>&>");
static_assert(std::is_constructible<gsl::span<const int, 3>, const gsl::span<const int>&>::value,
"std::is_constructible<gsl::span<const int, 3>, const gsl::span<const int>&>");
// no throw copy constructor // no throw copy constructor
static_assert(std::is_nothrow_copy_constructible<gsl::span<int>>::value, static_assert(std::is_nothrow_copy_constructible<gsl::span<int>>::value,
"std::is_nothrow_copy_constructible<gsl::span<int>>"); "std::is_nothrow_copy_constructible<gsl::span<int>>");

View File

@ -1144,7 +1144,7 @@ TEST(span_test, from_array_constructor)
// you can convert statically // you can convert statically
{ {
const span<int, 2> s2 = {&arr[0], 2}; const span<int, 2> s2{&arr[0], 2};
static_cast<void>(s2); static_cast<void>(s2);
} }
{ {
@ -1180,7 +1180,7 @@ TEST(span_test, from_array_constructor)
#endif #endif
{ {
auto f = [&]() { auto f = [&]() {
const span<int, 4> _s4 = {arr2, 2}; const span<int, 4> _s4{arr2, 2};
static_cast<void>(_s4); static_cast<void>(_s4);
}; };
EXPECT_DEATH(f(), deathstring); EXPECT_DEATH(f(), deathstring);