Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

<mdspan>: Make extents truly empty when rank_dynamic() == 0 #3825

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 22 additions & 16 deletions stl/inc/mdspan
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,19 @@ _STL_DISABLE_CLANG_WARNINGS
#undef new

_STD_BEGIN
template <class _IndexType, size_t _Size>
struct _Maybe_empty_array {
array<_IndexType, _Size> _Array{};
};

template <class _IndexType>
struct _Maybe_empty_array<_IndexType, 0> {};

template <size_t... _Extents>
inline constexpr size_t _Calculate_rank_dynamic = ((_Extents == dynamic_extent) + ... + 0);
JMazurkiewicz marked this conversation as resolved.
Show resolved Hide resolved

_EXPORT_STD template <class _IndexType, size_t... _Extents>
class extents {
class extents : private _Maybe_empty_array<_IndexType, _Calculate_rank_dynamic<_Extents...>> {
public:
using index_type = _IndexType;
using size_type = make_unsigned_t<index_type>;
Expand All @@ -39,8 +49,8 @@ public:
"Each element of Extents must be either equal to dynamic_extent, or must be representable as a value of type "
"IndexType (N4950 [mdspan.extents.overview]/1.2).");

static constexpr rank_type _Rank = sizeof...(_Extents);
static constexpr rank_type _Rank_dynamic = (static_cast<rank_type>(_Extents == dynamic_extent) + ... + 0);
static constexpr rank_type _Rank = sizeof...(_Extents);
static constexpr rank_type _Rank_dynamic = _Calculate_rank_dynamic<_Extents...>;
static constexpr array<rank_type, _Rank> _Static_extents = {_Extents...};
static constexpr bool _Multidim_index_space_size_is_always_zero = ((_Extents == 0) || ...);

Expand Down Expand Up @@ -76,14 +86,10 @@ private:
static constexpr array<rank_type, _Rank> _Dynamic_indices_inv = _Make_dynamic_indices_inv();

struct _Construct_from_tuple {
constexpr explicit _Construct_from_tuple() noexcept = default;
};

struct _Static_extents_only {
constexpr explicit _Static_extents_only() noexcept = default;
explicit _Construct_from_tuple() = default;
};

conditional_t<_Rank_dynamic != 0, array<index_type, _Rank_dynamic>, _Static_extents_only> _Dynamic_extents{};
using _Base = _Maybe_empty_array<_IndexType, _Rank_dynamic>;

public:
_NODISCARD static constexpr rank_type rank() noexcept {
Expand All @@ -108,10 +114,10 @@ public:
if constexpr (rank_dynamic() == 0) {
return static_cast<index_type>(_Static_extents[_Idx]);
} else if constexpr (rank_dynamic() == rank()) {
return _Dynamic_extents[_Idx];
return this->_Array[_Idx];
} else {
if (_Static_extents[_Idx] == dynamic_extent) {
return _Dynamic_extents[_Dynamic_indices[_Idx]];
return this->_Array[_Dynamic_indices[_Idx]];
} else {
return static_cast<index_type>(_Static_extents[_Idx]);
}
Expand All @@ -125,7 +131,7 @@ public:
&& ((_OtherExtents == dynamic_extent || _Extents == dynamic_extent || _OtherExtents == _Extents) && ...)
constexpr explicit extents(
const extents<_OtherIndexType, _OtherExtents...>& _Other, index_sequence<_Indices...>) noexcept
: _Dynamic_extents{static_cast<index_type>(_Other.extent(_Dynamic_indices_inv[_Indices]))...} {
: _Base{static_cast<index_type>(_Other.extent(_Dynamic_indices_inv[_Indices]))...} {
#if _CONTAINER_DEBUG_LEVEL > 0
if constexpr (rank() > 0) {
for (rank_type _Idx = 0; _Idx < _Rank; ++_Idx) {
Expand Down Expand Up @@ -154,12 +160,12 @@ public:
template <class _ExtsTuple, size_t... _Indices>
requires (tuple_size_v<_ExtsTuple> == rank_dynamic())
constexpr explicit extents(_Construct_from_tuple, _ExtsTuple _Tpl, index_sequence<_Indices...>) noexcept
: _Dynamic_extents{static_cast<index_type>(_STD move(_STD get<_Indices>(_Tpl)))...} {}
: _Base{static_cast<index_type>(_STD move(_STD get<_Indices>(_Tpl)))...} {}

template <class _ExtsTuple, size_t... _DynIndices>
requires (tuple_size_v<_ExtsTuple> != rank_dynamic())
constexpr explicit extents(_Construct_from_tuple, _ExtsTuple _Tpl, index_sequence<_DynIndices...>) noexcept
: _Dynamic_extents{static_cast<index_type>(_STD move(_STD get<_Dynamic_indices_inv[_DynIndices]>(_Tpl)))...} {
: _Base{static_cast<index_type>(_STD move(_STD get<_Dynamic_indices_inv[_DynIndices]>(_Tpl)))...} {
#if _CONTAINER_DEBUG_LEVEL > 0
[&]<size_t... _MixedIndices>(index_sequence<_MixedIndices...>) {
_STL_VERIFY(((_Static_extents[_MixedIndices] == dynamic_extent
Expand Down Expand Up @@ -199,7 +205,7 @@ public:
requires is_convertible_v<const _OtherIndexType&, index_type>
&& is_nothrow_constructible_v<index_type, const _OtherIndexType&> && (_Size == rank_dynamic())
constexpr explicit extents(span<_OtherIndexType, _Size> _Dynamic_exts, index_sequence<_Indices...>) noexcept
: _Dynamic_extents{static_cast<index_type>(_STD as_const(_Dynamic_exts[_Indices]))...} {
: _Base{static_cast<index_type>(_STD as_const(_Dynamic_exts[_Indices]))...} {
#if _CONTAINER_DEBUG_LEVEL > 0
if constexpr (_Is_standard_integer<_OtherIndexType> && _Size != 0) {
_STL_VERIFY(((_Dynamic_exts[_Indices] >= 0 && _STD in_range<index_type>(_Dynamic_exts[_Indices])) && ...),
Expand All @@ -213,7 +219,7 @@ public:
requires is_convertible_v<const _OtherIndexType&, index_type>
&& is_nothrow_constructible_v<index_type, const _OtherIndexType&> && (_Size != rank_dynamic())
constexpr explicit extents(span<_OtherIndexType, _Size> _Mixed_exts, index_sequence<_Indices...>) noexcept
: _Dynamic_extents{static_cast<index_type>(_STD as_const(_Mixed_exts[_Dynamic_indices_inv[_Indices]]))...} {
: _Base{static_cast<index_type>(_STD as_const(_Mixed_exts[_Dynamic_indices_inv[_Indices]]))...} {
#if _CONTAINER_DEBUG_LEVEL > 0
if constexpr (_Is_standard_integer<_OtherIndexType>) {
for (rank_type _Idx = 0; _Idx < _Rank; ++_Idx) {
Expand Down
6 changes: 6 additions & 0 deletions tests/std/tests/P0009R18_mdspan_extents/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -546,6 +546,12 @@ static_assert(all_extents_dynamic<dextents<unsigned int, 7>, 7>);
static_assert(all_extents_dynamic<dextents<unsigned long, 8>, 8>);
static_assert(all_extents_dynamic<dextents<unsigned long long, 9>, 9>);

// When 'E::rank_dynamic()' is equal to 0 then 'is_empty_v<E>' should be true (MSVC STL specific behavior)
static_assert(!is_empty_v<dextents<int, 2>>);
static_assert(!is_empty_v<extents<int, 3, dynamic_extent>>);
static_assert(is_empty_v<extents<int, 3, 3>>);
static_assert(is_empty_v<extents<int>>);

int main() {
static_assert(test());
test();
Expand Down