Skip to content
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
6 changes: 3 additions & 3 deletions stl/inc/mdspan
Original file line number Diff line number Diff line change
Expand Up @@ -601,7 +601,7 @@ public:
_Strides.back() = 1;
for (rank_type _Idx = extents_type::_Rank - 1; _Idx-- > 0;) {
// TRANSITION USE `_Multiply_with_overflow_check` IN DEBUG MODE
_Strides[_Idx] = _Strides[_Idx + 1] * _Exts.extent(_Idx + 1);
_Strides[_Idx] = static_cast<index_type>(_Strides[_Idx + 1] * _Exts.extent(_Idx + 1));
}
}
}
Expand Down Expand Up @@ -752,7 +752,7 @@ public:
}

for (rank_type _Idx = 0; _Idx < extents_type::_Rank; ++_Idx) {
if (_Left.stride(_Idx) != _Right.stride(_Idx)) {
if (_STD cmp_not_equal(_Left.stride(_Idx), _Right.stride(_Idx))) {
return false;
}
}
Expand Down Expand Up @@ -786,7 +786,7 @@ private:
template <class... _IndexTypes, size_t... _Seq>
_NODISCARD constexpr index_type _Index_impl(index_sequence<_Seq...>, _IndexTypes... _Indices) const noexcept {
_STL_INTERNAL_STATIC_ASSERT((same_as<_IndexTypes, index_type> && ...));
return ((_Indices * _Strides[_Seq]) + ... + 0);
return static_cast<index_type>(((_Indices * _Strides[_Seq]) + ... + 0));
Comment thread
StephanTLavavej marked this conversation as resolved.
}
};

Expand Down
63 changes: 63 additions & 0 deletions tests/std/include/test_mdspan_support.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@

#pragma once

#include <algorithm>
#include <concepts>
#include <cstddef>
#include <mdspan>
#include <span>
#include <type_traits>
#include <utility>

Expand Down Expand Up @@ -156,3 +158,64 @@ constexpr bool check_accessor_policy_requirements() {
static_assert(detail::CheckMemberFunctionsOfAccessorPolicy<A>);
return true;
}

namespace details {
template <size_t... Extents, class Fn>
constexpr void check_members_with_mixed_extents(Fn&& fn) {
auto select_extent = [](size_t e) consteval {
return e == std::dynamic_extent ? std::min(sizeof...(Extents), size_t{3}) : e;
};

// Check signed integers
fn(std::extents<signed char, Extents...>{select_extent(Extents)...});
fn(std::extents<short, Extents...>{select_extent(Extents)...});
fn(std::extents<int, Extents...>{select_extent(Extents)...});
fn(std::extents<long, Extents...>{select_extent(Extents)...});
fn(std::extents<long long, Extents...>{select_extent(Extents)...});

// Check unsigned integers
fn(std::extents<unsigned char, Extents...>{select_extent(Extents)...});
fn(std::extents<unsigned short, Extents...>{select_extent(Extents)...});
fn(std::extents<unsigned int, Extents...>{select_extent(Extents)...});
fn(std::extents<unsigned long, Extents...>{select_extent(Extents)...});
fn(std::extents<unsigned long long, Extents...>{select_extent(Extents)...});
}

template <class Fn, size_t... Seq>
constexpr void check_members_with_various_extents_impl(Fn&& fn, std::index_sequence<Seq...>) {
auto static_or_dynamic = [](size_t i) consteval {
return i == 0 ? std::dynamic_extent : std::min(sizeof...(Seq), size_t{3});
};

if constexpr (sizeof...(Seq) <= 1) {
check_members_with_mixed_extents<>(std::forward<Fn>(fn));
} else if constexpr (sizeof...(Seq) <= 2) {
(check_members_with_mixed_extents<static_or_dynamic(Seq)>(std::forward<Fn>(fn)), ...);
} else if constexpr (sizeof...(Seq) <= 4) {
(check_members_with_mixed_extents<static_or_dynamic(Seq & 0x2), static_or_dynamic(Seq & 0x1)>(
std::forward<Fn>(fn)),
...);
} else if constexpr (sizeof...(Seq) <= 8) {
(check_members_with_mixed_extents<static_or_dynamic(Seq & 0x4), static_or_dynamic(Seq & 0x2),
static_or_dynamic(Seq & 0x1)>(std::forward<Fn>(fn)),
...);
} else if constexpr (sizeof...(Seq) <= 16) {
(check_members_with_mixed_extents<static_or_dynamic(Seq & 0x8), static_or_dynamic(Seq & 0x4),
static_or_dynamic(Seq & 0x2), static_or_dynamic(Seq & 0x1)>(std::forward<Fn>(fn)),
...);
} else {
static_assert(sizeof...(Seq) <= 16, "We don't need more testing.");
}
}
} // namespace details

template <class Fn>
constexpr void check_members_with_various_extents(Fn&& fn) {
details::check_members_with_various_extents_impl(std::forward<Fn>(fn), std::make_index_sequence<1>{});
details::check_members_with_various_extents_impl(std::forward<Fn>(fn), std::make_index_sequence<2>{});
details::check_members_with_various_extents_impl(std::forward<Fn>(fn), std::make_index_sequence<4>{});
details::check_members_with_various_extents_impl(std::forward<Fn>(fn), std::make_index_sequence<8>{});
#ifndef _PREFAST_
details::check_members_with_various_extents_impl(std::forward<Fn>(fn), std::make_index_sequence<16>{});
#endif // _PREFAST_
}
17 changes: 5 additions & 12 deletions tests/std/tests/P0009R18_mdspan_extents/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
using namespace std;

template <class IndexType, size_t... Extents, size_t... Indices>
constexpr void do_check_members(index_sequence<Indices...>) {
constexpr void check_members(index_sequence<Indices...>) {
using Ext = extents<IndexType, Extents...>;

// Each specialization of extents models regular and is trivially copyable
Expand Down Expand Up @@ -80,11 +80,6 @@ constexpr void do_check_members(index_sequence<Indices...>) {
}
}

template <class IndexType, size_t... Extents>
constexpr void check_members() {
do_check_members<IndexType, Extents...>(make_index_sequence<sizeof...(Extents)>{});
}

constexpr void check_construction_from_other_extents() {
{ // Check construction from too big or too small other extents
using Ext = extents<int, 3, 3>;
Expand Down Expand Up @@ -292,16 +287,14 @@ constexpr void check_equality_operator() {
}

constexpr bool test() {
check_members<short>();
check_members<int, 1, 2, 3>();
check_members<unsigned short, 4, 4>();
check_members<unsigned long long, dynamic_extent, 4, 5>();
check_members<short, dynamic_extent, dynamic_extent, 6>();
check_members<unsigned char, dynamic_extent, dynamic_extent, dynamic_extent>();
check_members_with_various_extents([]<class IndexType, size_t... Extents>(const extents<IndexType, Extents...>&) {
check_members<IndexType, Extents...>(make_index_sequence<sizeof...(Extents)>{});
});
check_construction_from_other_extents();
check_construction_from_extents_pack();
check_construction_from_array_and_span();
check_equality_operator();

return true;
}

Expand Down
18 changes: 6 additions & 12 deletions tests/std/tests/P0009R18_mdspan_layout_left/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
using namespace std;

template <class IndexType, size_t... Extents, size_t... Indices>
constexpr void do_check_members(const extents<IndexType, Extents...>& ext, index_sequence<Indices...>) {
constexpr void check_members(const extents<IndexType, Extents...>& ext, index_sequence<Indices...>) {
using Ext = extents<IndexType, Extents...>;
using Mapping = layout_left::mapping<Ext>;

Expand Down Expand Up @@ -144,11 +144,6 @@ constexpr void do_check_members(const extents<IndexType, Extents...>& ext, index
}
}

template <class IndexType, size_t... Extents>
constexpr void check_members(extents<IndexType, Extents...> ext) {
do_check_members<IndexType, Extents...>(ext, make_index_sequence<sizeof...(Extents)>{});
}

constexpr void check_construction_from_other_left_mapping() {
{ // Check invalid construction
using Mapping = layout_left::mapping<extents<int, 3, 3>>;
Expand Down Expand Up @@ -356,18 +351,17 @@ constexpr void check_correctness() {
}

constexpr bool test() {
check_members(extents<short>{});
check_members(extents<int, 1, 2, 3>{});
check_members(extents<unsigned short, 4, 4>{});
check_members(extents<unsigned long long, dynamic_extent, 4, 5>{3});
check_members(extents<short, dynamic_extent, dynamic_extent, 6>{4, 5});
check_members(extents<unsigned char, dynamic_extent, dynamic_extent, dynamic_extent>{3, 3, 3});
check_members_with_various_extents(
[]<class IndexType, size_t... Extents>(const extents<IndexType, Extents...>& ext) {
check_members(ext, make_index_sequence<sizeof...(Extents)>{});
});
check_construction_from_other_left_mapping();
check_construction_from_other_right_mapping();
check_construction_from_other_stride_mapping();
check_call_operator();
check_comparisons();
check_correctness();

return true;
}

Expand Down
21 changes: 9 additions & 12 deletions tests/std/tests/P0009R18_mdspan_layout_right/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
using namespace std;

template <class IndexType, size_t... Extents, size_t... Indices>
constexpr void do_check_members(const extents<IndexType, Extents...>& ext, index_sequence<Indices...>) {
constexpr void check_members(const extents<IndexType, Extents...>& ext, index_sequence<Indices...>) {
using Ext = extents<IndexType, Extents...>;
using Mapping = layout_right::mapping<Ext>;

Expand Down Expand Up @@ -51,6 +51,8 @@ constexpr void do_check_members(const extents<IndexType, Extents...>& ext, index
using Ext2 = extents<OtherIndexType, Extents...>;
using Mapping2 = layout_right::mapping<Ext2>;

#pragma warning(push) // TRANSITION, "/analyze:only" BUG?
#pragma warning(disable : 28020) // The expression '0<=_Param_(1)&&_Param_(1)<=1-1' is not true at this call
{ // Check construction from other layout_right::mapping
Mapping m1{ext};
Mapping2 m2{m1};
Expand Down Expand Up @@ -138,11 +140,7 @@ constexpr void do_check_members(const extents<IndexType, Extents...>& ext, index
assert(!(m != m));
// Other tests are defined in 'check_comparisons' function
}
}

template <class IndexType, size_t... Extents>
constexpr void check_members(extents<IndexType, Extents...> ext) {
do_check_members<IndexType, Extents...>(ext, make_index_sequence<sizeof...(Extents)>{});
#pragma warning(pop) // TRANSITION, "/analyze:only" BUG?
}

constexpr void check_construction_from_other_right_mapping() {
Expand Down Expand Up @@ -367,18 +365,17 @@ constexpr void check_correctness() {
}

constexpr bool test() {
check_members(extents<short>{});
check_members(extents<int, 1, 2, 3>{});
check_members(extents<unsigned short, 4, 4>{});
check_members(extents<unsigned long long, dynamic_extent, 4, 5>{3});
check_members(extents<short, dynamic_extent, dynamic_extent, 6>{4, 5});
check_members(extents<unsigned char, dynamic_extent, dynamic_extent, dynamic_extent>{3, 3, 3});
check_members_with_various_extents(
[]<class IndexType, size_t... Extents>(const extents<IndexType, Extents...>& ext) {
check_members(ext, make_index_sequence<sizeof...(Extents)>{});
});
check_construction_from_other_right_mapping();
check_construction_from_other_left_mapping();
check_construction_from_other_stride_mapping();
check_call_operator();
check_comparisons();
check_correctness();

return true;
}

Expand Down
63 changes: 51 additions & 12 deletions tests/std/tests/P0009R18_mdspan_layout_stride/test.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#include <algorithm>
#include <array>
#include <cassert>
#include <concepts>
Expand All @@ -13,9 +14,16 @@

using namespace std;

template <class IndexType, size_t... Extents, size_t... Indices>
struct CmpEqual {
template <class T, class U>
[[nodiscard]] constexpr bool operator()(T t, U u) const noexcept {
return cmp_equal(t, u);
}
};

template <size_t... Extents, class IndexType, class StridesIndexType, size_t... Indices>
constexpr void do_check_members(const extents<IndexType, Extents...>& ext,
const array<IndexType, sizeof...(Extents)>& strs, index_sequence<Indices...>) {
const array<StridesIndexType, sizeof...(Extents)>& strs, index_sequence<Indices...>) {
using Ext = extents<IndexType, Extents...>;
using Strides = array<IndexType, sizeof...(Extents)>;
using Mapping = layout_stride::mapping<Ext>;
Expand Down Expand Up @@ -50,16 +58,16 @@ constexpr void do_check_members(const extents<IndexType, Extents...>& ext,
{ // Check construction from extents_type and array
Mapping m{ext, strs};
assert(m.extents() == ext);
assert(m.strides() == strs);
assert(ranges::equal(m.strides(), strs, CmpEqual{}));
static_assert(is_nothrow_constructible_v<Mapping, Ext, Strides>);
// Other tests are defined in 'check_construction_from_extents_and_array' function [FIXME]
}

{ // Check construction from extents_type and span
using Span = span<const IndexType, sizeof...(Extents)>;
using Span = span<const StridesIndexType, sizeof...(Extents)>;
Mapping m{ext, Span{strs}};
assert(m.extents() == ext);
assert(m.strides() == strs);
assert(ranges::equal(m.strides(), strs, CmpEqual{}));
static_assert(is_nothrow_constructible_v<Mapping, Ext, Span>);
// Other tests are defined in 'check_construction_from_extents_and_array' function [FIXME]
}
Expand All @@ -86,7 +94,7 @@ constexpr void do_check_members(const extents<IndexType, Extents...>& ext,

{ // Check 'strides' function
same_as<Strides> decltype(auto) strs2 = m.strides();
assert(strs2 == strs);
assert(ranges::equal(strs2, strs, CmpEqual{}));
static_assert(noexcept(m.strides()));
}

Expand Down Expand Up @@ -119,7 +127,7 @@ constexpr void do_check_members(const extents<IndexType, Extents...>& ext,
{ // Check 'stride' function
for (size_t i = 0; i < strs.size(); ++i) {
same_as<IndexType> decltype(auto) s = m.stride(i);
assert(strs[i] == s);
assert(cmp_equal(strs[i], s));
}
}

Expand All @@ -131,15 +139,46 @@ constexpr void do_check_members(const extents<IndexType, Extents...>& ext,
#pragma warning(pop) // TRANSITION, "/analyze:only" BUG?
}

template <class StridesIndexType, class IndexType, size_t... Extents>
constexpr void check_members_with_different_strides_index_type(
extents<IndexType, Extents...> ext, const array<int, sizeof...(Extents)>& strides) {
array<StridesIndexType, sizeof...(Extents)> test_strides;
ranges::transform(strides, test_strides.begin(), [](auto i) { return static_cast<StridesIndexType>(i); });
do_check_members<Extents...>(ext, test_strides, make_index_sequence<sizeof...(Extents)>{});
}

template <class IndexType, size_t... Extents>
constexpr void check_members(extents<IndexType, Extents...> ext, const array<IndexType, sizeof...(Extents)>& strides) {
do_check_members<IndexType, Extents...>(ext, strides, make_index_sequence<sizeof...(Extents)>{});
constexpr void check_members(extents<IndexType, Extents...> ext, const array<int, sizeof...(Extents)>& strides) {
// Check signed strides
check_members_with_different_strides_index_type<signed char>(ext, strides);
check_members_with_different_strides_index_type<short>(ext, strides);
check_members_with_different_strides_index_type<int>(ext, strides);
check_members_with_different_strides_index_type<long>(ext, strides);
check_members_with_different_strides_index_type<long long>(ext, strides);

// Check unsigned strides
check_members_with_different_strides_index_type<unsigned char>(ext, strides);
check_members_with_different_strides_index_type<unsigned short>(ext, strides);
check_members_with_different_strides_index_type<unsigned int>(ext, strides);
check_members_with_different_strides_index_type<unsigned long>(ext, strides);
check_members_with_different_strides_index_type<unsigned long long>(ext, strides);
}

constexpr bool test() {
check_members(extents<short>{}, array<short, 0>{});
check_members(extents<long, 4>{}, array<long, 1>{1});
check_members(extents<int, 3, dynamic_extent>{3}, array<int, 2>{1, 3});
// Check signed integers
check_members(extents<signed char, 5>{5}, array{1});
check_members(extents<short, 6, 7>{}, array{1, 6});
check_members(extents<int, 3, dynamic_extent>{3}, array{1, 3});
check_members(extents<long, 4>{}, array{1});
check_members(extents<long long, 3, 2, dynamic_extent>{3}, array{1, 3, 6});

// Check unsigned integers
check_members(extents<unsigned char, 5>{5}, array{1});
check_members(extents<unsigned short, 6, 7>{}, array{1, 6});
check_members(extents<unsigned int, 3, dynamic_extent>{3}, array{1, 3});
check_members(extents<unsigned long, 4>{}, array{1});
check_members(extents<unsigned long long, 3, 2, dynamic_extent>{3}, array{1, 3, 6});

// TRANSITION more tests
return true;
}
Expand Down