Skip to content

Commit

Permalink
<mdspan>: More EBO (#3847)
Browse files Browse the repository at this point in the history
  • Loading branch information
JMazurkiewicz committed Jul 6, 2023
1 parent 2a12d44 commit 7943441
Show file tree
Hide file tree
Showing 7 changed files with 309 additions and 110 deletions.
287 changes: 207 additions & 80 deletions stl/inc/mdspan

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#define intrinsic 3
#define lifetimebound 4
#define noop_dtor 5
#define empty_bases 6

#include <__msvc_all_public_headers.hpp>

Expand All @@ -35,3 +36,7 @@
#if noop_dtor != 5
#error bad macro expansion
#endif // noop_dtor != 5

#if empty_bases != 6
#error bad macro expansion
#endif // noop_dtor != 6
3 changes: 3 additions & 0 deletions tests/std/tests/P0009R18_mdspan_default_accessor/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ constexpr void test_one(array<ElementType, 3> elems) {
static_assert(is_trivially_copyable_v<Accessor>);
static_assert(semiregular<Accessor>);

// Check if default_accessor is empty
static_assert(std::is_empty_v<Accessor>);

// Check nested types
static_assert(same_as<typename Accessor::offset_policy, Accessor>);
static_assert(same_as<typename Accessor::element_type, ElementType>);
Expand Down
13 changes: 13 additions & 0 deletions tests/std/tests/P0009R18_mdspan_layout_left/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,10 @@ constexpr void check_correctness() {
#endif // ^^^ !defined(__cpp_multidimensional_subscript) ^^^
}


#ifdef __clang__
if (!is_constant_evaluated()) // FIXME clang hits constexpr limit here
#endif
{ // 3x2 matrix with column-major order
const array values{0, 1, 2, 3, 4, 5};
mdspan<const int, extents<int, 3, 2>, layout_left> matrix{values.data()};
Expand All @@ -444,6 +448,9 @@ constexpr void check_correctness() {
#endif // ^^^ !defined(__cpp_multidimensional_subscript) ^^^
}

#ifdef __clang__
if (!is_constant_evaluated()) // FIXME clang hits constexpr limit here
#endif
{ // 3x2x4 tensor
const array values{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23};
mdspan<const int, dextents<size_t, 3>, layout_left> tensor{values.data(), 3, 2, 4};
Expand Down Expand Up @@ -493,6 +500,12 @@ constexpr void check_correctness() {
}
}

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

constexpr bool test() {
check_members_with_various_extents([]<class E>(const E& e) { check_members(e, make_index_sequence<E::rank()>{}); });
if (!is_constant_evaluated()) { // too heavy for compile time
Expand Down
6 changes: 6 additions & 0 deletions tests/std/tests/P0009R18_mdspan_layout_right/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -516,6 +516,12 @@ constexpr void check_correctness() {
}
}

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

constexpr bool test() {
check_members_with_various_extents([]<class E>(const E& e) { check_members(e, make_index_sequence<E::rank()>{}); });
if (!is_constant_evaluated()) { // too heavy for compile time
Expand Down
6 changes: 6 additions & 0 deletions tests/std/tests/P0009R18_mdspan_layout_stride/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -821,6 +821,12 @@ constexpr void check_correctness() {
}
}

// When 'M::extents_type::rank()' is equal to 0 then 'is_empty_v<M>' should be true (MSVC STL specific behavior)
static_assert(!is_empty_v<layout_stride::mapping<dextents<long long, 2>>>);
static_assert(!is_empty_v<layout_stride::mapping<extents<long long, 3, dynamic_extent>>>);
static_assert(!is_empty_v<layout_stride::mapping<extents<long long, 3, 3>>>);
static_assert(is_empty_v<layout_stride::mapping<extents<long long>>>);

constexpr bool test() {
// Check signed integers
check_members(extents<signed char, 5>{5}, array{1});
Expand Down
99 changes: 69 additions & 30 deletions tests/std/tests/P0009R18_mdspan_mdspan/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1095,35 +1095,52 @@ constexpr void check_empty() {
}

constexpr void check_swap() {
using E = extents<int, 3, 3>;
using Mds = mdspan<int, E, TrackingLayout<>, TrackingAccessor<int>>;
static_assert(is_nothrow_swappable_v<Mds>);
static_assert(!is_swappable_v<const Mds>);

int a1[9] = {1, 0, 0, 0, 1, 0, 0, 0, 1};
Mds mds1{TrackingDataHandle<int>{1, a1}, TrackingLayout<>::mapping<E>(1), TrackingAccessor<int>{1}};
int a2[9] = {3, 0, 0, 0, 3, 0, 0, 0, 3};
Mds mds2{TrackingDataHandle<int>{3, a2}, TrackingLayout<>::mapping<E>(3), TrackingAccessor<int>{3}};
swap(mds1, mds2);
static_assert(is_void_v<decltype(swap(mds1, mds2))>);

assert(mds1.data_handle().get_id() == 3);
assert(mds1.data_handle().is_swapped());
assert(mds1.mapping().get_id() == 3);
assert(mds1.mapping().is_swapped());
assert(mds1.accessor().get_id() == 3);
assert(mds1.accessor().is_swapped());
assert((mds1[array{1, 1}] == 3));
assert((mds1[array{0, 1}] == 0));

assert(mds2.data_handle().get_id() == 1);
assert(mds2.data_handle().is_swapped());
assert(mds2.mapping().get_id() == 1);
assert(mds2.mapping().is_swapped());
assert(mds2.accessor().get_id() == 1);
assert(mds2.accessor().is_swapped());
assert((mds2[array{1, 1}] == 1));
assert((mds2[array{0, 1}] == 0));
{ // Check swapping with tracking types
using E = extents<int, 3, 3>;
using Mds = mdspan<int, E, TrackingLayout<>, TrackingAccessor<int>>;
static_assert(is_nothrow_swappable_v<Mds>);
static_assert(!is_swappable_v<const Mds>);

int a1[9] = {1, 0, 0, 0, 1, 0, 0, 0, 1};
Mds mds1{TrackingDataHandle<int>{1, a1}, TrackingLayout<>::mapping<E>(1), TrackingAccessor<int>{1}};
int a2[9] = {3, 0, 0, 0, 3, 0, 0, 0, 3};
Mds mds2{TrackingDataHandle<int>{3, a2}, TrackingLayout<>::mapping<E>(3), TrackingAccessor<int>{3}};
swap(mds1, mds2);
static_assert(is_void_v<decltype(swap(mds1, mds2))>);

assert(mds1.data_handle().get_id() == 3);
assert(mds1.data_handle().is_swapped());
assert(mds1.mapping().get_id() == 3);
assert(mds1.mapping().is_swapped());
assert(mds1.accessor().get_id() == 3);
assert(mds1.accessor().is_swapped());
assert((mds1[array{1, 1}] == 3));
assert((mds1[array{0, 1}] == 0));

assert(mds2.data_handle().get_id() == 1);
assert(mds2.data_handle().is_swapped());
assert(mds2.mapping().get_id() == 1);
assert(mds2.mapping().is_swapped());
assert(mds2.accessor().get_id() == 1);
assert(mds2.accessor().is_swapped());
assert((mds2[array{1, 1}] == 1));
assert((mds2[array{0, 1}] == 0));
}

{ // Check swapping with standard layout and accessor
using Mds = mdspan<int, extents<int, 2, 2>>;
static_assert(is_nothrow_swappable_v<Mds>);
static_assert(!is_swappable_v<const Mds>);

int diag[] = {1, 0, 0, 1};
Mds mds1{diag};
int revdiag[] = {0, 1, 1, 0};
Mds mds2{revdiag};

swap(mds1, mds2);
assert(mds1.data_handle() == revdiag);
assert(mds2.data_handle() == diag);
}
}

constexpr void check_getters() {
Expand Down Expand Up @@ -1316,11 +1333,33 @@ constexpr void check_deduction_guides() {
}
}

// When
// * 'Mds::accessor_type' is specialization of 'default_accesor', and
// * 'Mds::layout_type' is
// * 'layout_left' or 'layout_right' and 'Mds::extents_type::rank_dynamic() == 0', or
// * 'layout_stride' and 'Mds::extents_type::rank() == 0'
// then 'sizeof(Mds) == sizeof(void*)' (MSVC STL specific behavior).
static_assert(sizeof(mdspan<int, extents<int, 3, 3, 3>, layout_left>) == sizeof(void*));
static_assert(sizeof(mdspan<int, dextents<int, 3>, layout_left>) > sizeof(void*));
static_assert(sizeof(mdspan<int, extents<int, 3, 3, 3>, layout_left, TrivialAccessor<int>>) > sizeof(void*));

static_assert(sizeof(mdspan<long, extents<long, 2, 2, 2>, layout_right>) == sizeof(void*));
static_assert(sizeof(mdspan<long, dextents<long, 2>, layout_right>) > sizeof(void*));
static_assert(sizeof(mdspan<long, extents<long, 2, 2, 2>, layout_right, TrivialAccessor<long>>) > sizeof(void*));

static_assert(sizeof(mdspan<short, extents<short>, layout_stride>) == sizeof(void*));
static_assert(sizeof(mdspan<short, extents<short, 4, 4, 4>, layout_stride>) > sizeof(void*));
static_assert(sizeof(mdspan<short, dextents<short, 4>, layout_stride>) > sizeof(void*));
static_assert(sizeof(mdspan<short, extents<short, 4, 4, 4>, layout_stride, TrivialAccessor<short>>) > sizeof(void*));

constexpr bool test() {
check_modeled_concepts_and_member_types<dextents<unsigned long long, 3>, layout_left, default_accessor>();
check_modeled_concepts_and_member_types<dextents<unsigned long long, 3>, layout_right, default_accessor>();
check_modeled_concepts_and_member_types<dextents<unsigned long long, 3>, layout_stride, default_accessor>();
check_modeled_concepts_and_member_types<dextents<unsigned long long, 3>, layout_left, TrackingAccessor>();
check_modeled_concepts_and_member_types<extents<signed char, 2, 3, 5>, layout_stride, TrivialAccessor>();
check_modeled_concepts_and_member_types<extents<unsigned short, 2, 4, dynamic_extent>, TrackingLayout<>,
AccessorWithTrackingDataHandle>();
check_modeled_concepts_and_member_types<dextents<unsigned long long, 3>, layout_left, TrackingAccessor>();
check_observers();
check_default_constructor();
check_defaulted_copy_and_move_constructors();
Expand Down

0 comments on commit 7943441

Please sign in to comment.