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>: Check preconditions of mdspan::operator[] clarified by LWG-3974 #4214

Merged
merged 2 commits into from
Nov 29, 2023
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
24 changes: 24 additions & 0 deletions stl/inc/mdspan
Original file line number Diff line number Diff line change
Expand Up @@ -1131,6 +1131,22 @@ struct _Mdspan_accessor_base<_AccessorPolicy> {
static constexpr _AccessorPolicy _Acc{};
};

#if _CONTAINER_DEBUG_LEVEL > 0
template <class _IndexType, class _OtherIndexType>
_NODISCARD constexpr _IndexType _Mdspan_checked_index_cast(_OtherIndexType&& _Idx) noexcept(
is_nothrow_constructible_v<_IndexType, _OtherIndexType>) {
_STL_INTERNAL_STATIC_ASSERT(is_integral_v<_IndexType> && is_constructible_v<_IndexType, _OtherIndexType>);

using _Arg_value_t = remove_cvref_t<_OtherIndexType>;
if constexpr (is_integral_v<_Arg_value_t> && !is_same_v<_Arg_value_t, bool>) {
_STL_VERIFY(_STD in_range<_IndexType>(_Idx),
"Each argument to operator[] must be representable by index_type in order for the pack of arguments to be "
"a valid multidimensional index (N4964 [mdspan.mdspan.members]/3).");
}
return static_cast<_IndexType>(_STD forward<_OtherIndexType>(_Idx));
}
#endif // _CONTAINER_DEBUG_LEVEL > 0

_EXPORT_STD template <class _ElementType, class _Extents, class _LayoutPolicy = layout_right,
class _AccessorPolicy = default_accessor<_ElementType>>
class __declspec(empty_bases) mdspan : private _Mdspan_mapping_base<_Extents, _LayoutPolicy>,
Expand Down Expand Up @@ -1278,7 +1294,11 @@ public:
&& (sizeof...(_OtherIndexTypes) == rank())
_NODISCARD constexpr reference operator[](_OtherIndexTypes... _Indices) const
noexcept(noexcept(_Access_impl(static_cast<index_type>(_STD move(_Indices))...))) /* strengthened */ {
#if _CONTAINER_DEBUG_LEVEL > 0
return _Access_impl(_STD _Mdspan_checked_index_cast<index_type>(_STD move(_Indices))...);
#else // ^^^ _CONTAINER_DEBUG_LEVEL > 0 / _CONTAINER_DEBUG_LEVEL <= 0 vvv
return _Access_impl(static_cast<index_type>(_STD move(_Indices))...);
#endif // ^^^ _CONTAINER_DEBUG_LEVEL <= 0 ^^^
}
#endif // ^^^ defined(__cpp_multidimensional_subscript) ^^^

Expand All @@ -1287,7 +1307,11 @@ private:
_NODISCARD constexpr reference _Multidimensional_subscript(
span<_OtherIndexType, rank()> _Indices, index_sequence<_Seq...>) const
noexcept(noexcept(_Access_impl(static_cast<index_type>(_STD as_const(_Indices[_Seq]))...))) {
#if _CONTAINER_DEBUG_LEVEL > 0
return _Access_impl(_STD _Mdspan_checked_index_cast<index_type>(_STD as_const(_Indices[_Seq]))...);
#else // ^^^ _CONTAINER_DEBUG_LEVEL > 0 / _CONTAINER_DEBUG_LEVEL <= 0 vvv
return _Access_impl(static_cast<index_type>(_STD as_const(_Indices[_Seq]))...);
#endif // ^^^ _CONTAINER_DEBUG_LEVEL <= 0 ^^^
}

public:
Expand Down
12 changes: 12 additions & 0 deletions tests/std/tests/P0009R18_mdspan_mdspan_death/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ void test_access_with_invalid_multidimensional_index_1() {
// I must be a multidimensional index in extents()
(void) mds[3, 4];
}

void test_access_with_nonrepresentable_index_1() {
mdspan mds{some_ints.data(), dextents<unsigned char, 2>{2, 3}};
(void) mds[256u, -255];
}
#endif // __cpp_multidimensional_subscript

void test_access_with_invalid_multidimensional_index_2() {
Expand All @@ -33,6 +38,11 @@ void test_access_with_invalid_multidimensional_index_2() {
(void) mds[array{4, 5}];
}

void test_access_with_nonrepresentable_index_2() {
mdspan mds{some_ints.data(), dextents<unsigned char, 2>{2, 3}};
(void) mds[array{256, -255}];
}

void test_size_when_index_type_is_signed() {
mdspan mds{some_ints.data(), dextents<signed char, 3>{8, 8, 4}};
// The size of the multidimensional index space extents() must be representable as a value of type size_type
Expand All @@ -51,8 +61,10 @@ int main(int argc, char* argv[]) {
test_construction_from_other_mdspan,
#ifdef __cpp_multidimensional_subscript // TRANSITION, P2128R6
test_access_with_invalid_multidimensional_index_1,
test_access_with_nonrepresentable_index_1,
#endif // __cpp_multidimensional_subscript
test_access_with_invalid_multidimensional_index_2,
test_access_with_nonrepresentable_index_2,
test_size_when_index_type_is_signed,
test_size_when_index_type_is_unsigned,
});
Expand Down