Skip to content

Commit

Permalink
<mdspan>: Make extents truly empty when rank_dynamic() == 0
Browse files Browse the repository at this point in the history
* Introduce `_Calculate_rank_dynamic` template variable for easier `rank_dynamic()` computations,
* Introduce `_Dynamic_extents_array` - a base class for `std::extents`,
* Remove `extents::_Static_extents_only` and `extents::_Dynamic_extents`,
* Add tests.
  • Loading branch information
JMazurkiewicz committed Jun 23, 2023
1 parent 652e2b0 commit c87fbc5
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 15 deletions.
37 changes: 22 additions & 15 deletions stl/inc/mdspan
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,20 @@ _STL_DISABLE_CLANG_WARNINGS
#undef new

_STD_BEGIN
template <size_t... _Extents>
inline constexpr size_t _Calculate_rank_dynamic = ((_Extents == dynamic_extent) + ... + 0);

template <class _IndexType, size_t... _Extents>
struct _Dynamic_extents_array {
array<_IndexType, _Calculate_rank_dynamic<_Extents...>> _Dynamic_extents{};
};

template <class _IndexType, size_t... _Extents>
requires (_Calculate_rank_dynamic<_Extents...> == 0)
struct _Dynamic_extents_array<_IndexType, _Extents...> {};

_EXPORT_STD template <class _IndexType, size_t... _Extents>
class extents {
class extents : private _Dynamic_extents_array<_IndexType, _Extents...> {
public:
using index_type = _IndexType;
using size_type = make_unsigned_t<index_type>;
Expand All @@ -40,7 +51,7 @@ public:
"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_dynamic = _Calculate_rank_dynamic<_Extents...>;

private:
static constexpr array<rank_type, _Rank> _Static_extents = {_Extents...};
Expand Down Expand Up @@ -76,14 +87,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 = _Dynamic_extents_array<_IndexType, _Extents...>;

public:
_NODISCARD static constexpr rank_type rank() noexcept {
Expand All @@ -108,10 +115,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->_Dynamic_extents[_Idx];
} else {
if (_Static_extents[_Idx] == dynamic_extent) {
return _Dynamic_extents[_Dynamic_indices[_Idx]];
return this->_Dynamic_extents[_Dynamic_indices[_Idx]];
} else {
return static_cast<index_type>(_Static_extents[_Idx]);
}
Expand All @@ -125,7 +132,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 +161,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 @@ -196,7 +203,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 @@ -210,7 +217,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

0 comments on commit c87fbc5

Please sign in to comment.