-
Notifications
You must be signed in to change notification settings - Fork 1.6k
<mdspan>: Add separate tests for extents and default_accessor
#3580
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
Merged
Stephan T. Lavavej (StephanTLavavej)
merged 11 commits into
microsoft:feature/mdspan2
from
JMazurkiewicz:mdspan/tests
Mar 17, 2023
Merged
Changes from all commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
c9a884c
Restore `<type_traits>` include in `<mdspan>` header
JMazurkiewicz 7d51c11
Test `default_accessor`
JMazurkiewicz 27997ce
Test `extents`
JMazurkiewicz 161df22
Fix `default_accessor` tests
JMazurkiewicz b5525a0
Try to fix CI
JMazurkiewicz 2137d3d
Extra coverage for empty `extents`
JMazurkiewicz c562fa1
Address review comments
JMazurkiewicz f45153b
Extra checks for `default_accessor`
JMazurkiewicz 42e5bc7
`DefaultAccessor` -> `Accessor`
JMazurkiewicz b5bab90
QUICK: FIX THIS AWFUL FORMATTING
JMazurkiewicz b744dea
AGAIN 🤦🤦🤦
JMazurkiewicz File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| # Copyright (c) Microsoft Corporation. | ||
| # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
|
|
||
| RUNALL_INCLUDE ..\concepts_latest_matrix.lst |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,66 @@ | ||
| // Copyright (c) Microsoft Corporation. | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
|
|
||
| #include <array> | ||
| #include <cassert> | ||
| #include <concepts> | ||
| #include <cstdint> | ||
| #include <mdspan> | ||
| #include <string> | ||
| #include <type_traits> | ||
|
|
||
| using namespace std; | ||
|
|
||
| template <class ElementType> | ||
| constexpr void test_one(array<ElementType, 3> elems) { | ||
| using Accessor = default_accessor<ElementType>; | ||
|
|
||
| // Check modeled concepts | ||
| static_assert(is_nothrow_move_constructible_v<Accessor>); | ||
| static_assert(is_nothrow_move_assignable_v<Accessor>); | ||
| static_assert(is_nothrow_swappable_v<Accessor>); | ||
| static_assert(is_trivially_copyable_v<Accessor>); | ||
| static_assert(semiregular<Accessor>); | ||
|
|
||
| // Check nested types | ||
| static_assert(same_as<typename Accessor::offset_policy, Accessor>); | ||
| static_assert(same_as<typename Accessor::element_type, ElementType>); | ||
| static_assert(same_as<typename Accessor::reference, ElementType&>); | ||
| static_assert(same_as<typename Accessor::data_handle_type, ElementType*>); | ||
|
|
||
| // Check default constructor | ||
| Accessor accessor; | ||
| static_assert(is_nothrow_default_constructible_v<Accessor>); | ||
|
|
||
| { // Check converting constructor from other accessor | ||
| [[maybe_unused]] default_accessor<const ElementType> const_accessor = accessor; | ||
| static_assert(is_nothrow_constructible_v<default_accessor<const ElementType>, Accessor>); | ||
| static_assert(!is_constructible_v<Accessor, default_accessor<const ElementType>>); | ||
| } | ||
|
|
||
| { // Check 'access' member function | ||
| same_as<ElementType&> decltype(auto) accessed_elem = accessor.access(elems.data(), 1); | ||
| assert(accessed_elem == elems[1]); | ||
| static_assert(noexcept(accessor.access(elems.data(), 0))); | ||
| } | ||
|
|
||
| { // Check 'offset' member function | ||
| same_as<ElementType*> auto ptr = accessor.offset(elems.data(), 1); | ||
| assert(ptr == elems.data() + 1); | ||
| static_assert(noexcept(accessor.offset(elems.data(), 0))); | ||
| } | ||
| } | ||
|
|
||
| constexpr bool test() { | ||
| test_one<char>({'a', 'b', 'c'}); | ||
| test_one<long>({1, 2, 3}); | ||
| test_one<double>({1.1, 2.2, 3.3}); | ||
| test_one<wstring>({L"1", L"2", L"3"}); | ||
| test_one<intmax_t>({3, 2, 1}); | ||
| return true; | ||
| } | ||
|
|
||
| int main() { | ||
| static_assert(test()); | ||
| test(); | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| # Copyright (c) Microsoft Corporation. | ||
| # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
|
|
||
| RUNALL_INCLUDE ..\concepts_latest_matrix.lst |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,295 @@ | ||
| // Copyright (c) Microsoft Corporation. | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
|
|
||
| #include <array> | ||
| #include <cassert> | ||
| #include <concepts> | ||
| #include <mdspan> | ||
| #include <span> | ||
| #include <type_traits> | ||
| #include <utility> | ||
|
|
||
| using namespace std; | ||
|
|
||
| enum class IsNothrow : bool { no, yes }; | ||
|
|
||
| template <class Int, IsNothrow Nothrow = IsNothrow::yes> | ||
| struct ConvertibleToInt { | ||
| constexpr operator Int() const noexcept(to_underlying(Nothrow)) { | ||
| return Int{1}; | ||
| } | ||
| }; | ||
|
|
||
| struct NonConvertibleToAnything {}; | ||
|
|
||
| template <class T> | ||
| constexpr void check_implicit_conversion(T); // not defined | ||
|
|
||
| // clang-format off | ||
| template <class T, class... Args> | ||
| concept NotImplicitlyConstructibleFrom = | ||
| constructible_from<T, Args...> | ||
| && !requires(Args&&... args) { check_implicit_conversion<T>({forward<Args>(args)...}); }; | ||
| // clang-format on | ||
|
|
||
| template <class IndexType, size_t... Extents, size_t... Indices> | ||
| constexpr void do_check_members(index_sequence<Indices...>) { | ||
| using Ext = extents<IndexType, Extents...>; | ||
|
|
||
| // Each specialization of extents models regular and is trivially copyable | ||
| static_assert(regular<Ext>); | ||
| static_assert(is_trivially_copyable_v<Ext>); | ||
|
|
||
| // Check member types | ||
| static_assert(same_as<typename Ext::index_type, IndexType>); | ||
| static_assert(same_as<typename Ext::size_type, make_unsigned_t<IndexType>>); | ||
| static_assert(same_as<typename Ext::rank_type, size_t>); | ||
|
|
||
| // Check static observers | ||
| static_assert(Ext::rank() == sizeof...(Extents)); | ||
| static_assert(Ext::rank_dynamic() == ((Extents == dynamic_extent) + ... + 0)); | ||
| static_assert(((Ext::static_extent(Indices) == Extents) && ...)); | ||
|
|
||
| // Check noexceptness of static observers | ||
| static_assert(noexcept(Ext::rank())); | ||
| static_assert(noexcept(Ext::rank_dynamic())); | ||
| static_assert(noexcept(Ext::static_extent(0))); | ||
|
|
||
| // Check default constructor | ||
| Ext ext; | ||
| static_assert(is_nothrow_default_constructible_v<Ext>); | ||
|
|
||
| // Check 'extent' observer | ||
| assert((((ext.extent(Indices) == Extents && Extents != dynamic_extent) || ext.extent(Indices) == 0) && ...)); | ||
|
|
||
| using OtherIndexType = conditional_t<is_signed_v<IndexType>, long long, unsigned long long>; | ||
| using Ext2 = extents<OtherIndexType, Extents...>; | ||
|
|
||
| { // Check construction from other extents | ||
| Ext2 ext2{ext}; | ||
| assert(((ext.extent(Indices) == ext2.extent(Indices)) && ...)); | ||
| assert(ext == ext2); | ||
| static_assert(is_nothrow_constructible_v<Ext2, Ext>); | ||
| // Other tests are defined in 'check_construction_from_other_extents' function | ||
| } | ||
|
|
||
| { // Check construction from extents pack | ||
| Ext2 ext2{ext.extent(Indices)...}; | ||
| assert(((ext.extent(Indices) == ext2.extent(Indices)) && ...)); | ||
| assert(ext == ext2); | ||
| static_assert(is_nothrow_constructible_v<Ext2, Ext>); | ||
| // Other tests are defined in 'check_construction_from_extents_pack' function | ||
| } | ||
|
|
||
| { // Check construction from array and span | ||
| auto arr = to_array<IndexType>({ext.extent(Indices)...}); | ||
| Ext2 ext2a{arr}; | ||
| assert(((ext.extent(Indices) == ext2a.extent(Indices)) && ...)); | ||
| assert(ext == ext2a); | ||
| static_assert(is_nothrow_constructible_v<Ext2, decltype(arr)>); | ||
|
|
||
| span s{arr}; | ||
| Ext2 ext2b{s}; | ||
| assert(((ext.extent(Indices) == ext2b.extent(Indices)) && ...)); | ||
| assert(ext == ext2b); | ||
| static_assert(is_nothrow_constructible_v<Ext2, decltype(s)>); | ||
| // Other tests are defined in 'check_construction_from_array_and_span' function | ||
| } | ||
| } | ||
|
|
||
| template <class IndexType, size_t... Extents> | ||
| constexpr void check_members() { | ||
| do_check_members<IndexType, Extents...>(make_index_sequence<sizeof...(Extents)>{}); | ||
|
JMazurkiewicz marked this conversation as resolved.
|
||
| } | ||
|
|
||
| constexpr void check_construction_from_other_extents() { | ||
| { // Check construction from too big or too small other extents | ||
| using Ext = extents<int, 3, 3>; | ||
| static_assert(!is_constructible_v<Ext, int>); | ||
| static_assert(!is_constructible_v<Ext, extents<int, 3, 3, 3>>); | ||
| } | ||
|
|
||
| { // Check construction with different values | ||
| static_assert(is_nothrow_constructible_v<extents<int, 3, 3>, extents<int, 3, 3>>); | ||
| static_assert(is_nothrow_constructible_v<extents<int, 3, 3>, extents<int, 3, dynamic_extent>>); | ||
| static_assert(is_nothrow_constructible_v<extents<int, 3, dynamic_extent>, extents<int, 3, 3>>); | ||
| static_assert(is_nothrow_constructible_v<extents<int, 3, dynamic_extent>, extents<int, 3, dynamic_extent>>); | ||
| static_assert(!is_constructible_v<extents<int, 3, 3>, extents<int, 3, 2>>); | ||
| } | ||
|
|
||
| { // Check postconditions | ||
| extents<int, dynamic_extent, dynamic_extent> ext{4, 4}; | ||
| extents<int, 4, 4> ext2{ext}; | ||
| assert(ext == ext2); | ||
| assert(ext2.extent(0) == 4); | ||
| assert(ext2.extent(1) == 4); | ||
|
|
||
| extents<long, 4, dynamic_extent> ext3{ext}; | ||
| assert(ext == ext3); | ||
| assert(ext3.extent(0) == 4); | ||
| assert(ext3.extent(1) == 4); | ||
| } | ||
|
|
||
| { // Check implicit conversions | ||
| static_assert(!NotImplicitlyConstructibleFrom<extents<int, 3>, extents<int, 3>>); | ||
| static_assert(NotImplicitlyConstructibleFrom<extents<int, 3>, extents<long long, 3>>); | ||
| static_assert(NotImplicitlyConstructibleFrom<extents<int, 3, 3>, extents<int, dynamic_extent, 3>>); | ||
| static_assert(NotImplicitlyConstructibleFrom<extents<int, 3, 3>, extents<int, dynamic_extent, dynamic_extent>>); | ||
| } | ||
| } | ||
|
|
||
| constexpr void check_construction_from_extents_pack() { | ||
| { // Check construction from various types | ||
| using Ext = extents<int, 3, 3, dynamic_extent, dynamic_extent>; | ||
| static_assert(is_nothrow_constructible_v<Ext, int, int>); | ||
| static_assert(!is_constructible_v<Ext, int, int, int>); | ||
| static_assert(is_nothrow_constructible_v<Ext, int, int, int, int>); | ||
| } | ||
|
|
||
| { // Check construction from types (not) convertible to index_type | ||
| using Ext = extents<long, 2, dynamic_extent>; | ||
| static_assert(is_nothrow_constructible_v<Ext, ConvertibleToInt<int>>); | ||
| static_assert(!is_constructible_v<Ext, NonConvertibleToAnything>); | ||
| static_assert(is_nothrow_constructible_v<Ext, int, ConvertibleToInt<int>>); | ||
| static_assert(!is_constructible_v<Ext, int, NonConvertibleToAnything>); | ||
| } | ||
|
|
||
| { // Check construction from types that may throw during conversion to index_type | ||
| using Ext = extents<long long, 4, dynamic_extent>; | ||
| static_assert(!is_constructible_v<Ext, ConvertibleToInt<int, IsNothrow::no>>); | ||
| static_assert(!is_constructible_v<Ext, int, ConvertibleToInt<int, IsNothrow::no>>); | ||
| } | ||
|
|
||
| #if 0 // FIXME Bug in array/span constructor? | ||
| { // Check postconditions [FIXME] | ||
| using Ext = extents<int, dynamic_extent, dynamic_extent, 4>; | ||
| array<int, 3> arr = {4, 4, 4}; | ||
| Ext ext{arr}; | ||
| Ext ext2{4, 4, 4}; | ||
| assert(ext == ext2); | ||
| } | ||
| #endif // Bug? | ||
|
|
||
| { // Check implicit conversions | ||
| static_assert(NotImplicitlyConstructibleFrom<extents<int, 3>, unsigned long long>); | ||
| static_assert(NotImplicitlyConstructibleFrom<extents<int, 3, 3>, long, long>); | ||
| static_assert(NotImplicitlyConstructibleFrom<extents<int, 3, 3, 3>, char, signed char, unsigned char>); | ||
| } | ||
| } | ||
|
|
||
| constexpr void check_construction_from_array_and_span() { | ||
| { // Check construction from arrays/spans with elements (not) convertible to index_type | ||
| using Ext = extents<short, 4, dynamic_extent>; | ||
|
|
||
| array<int, 2> arr1 = {4, 5}; | ||
| Ext ext1a{arr1}; | ||
| span s1{arr1}; | ||
| Ext ext1b{s1}; | ||
| assert(ext1a == ext1b); | ||
| static_assert(is_nothrow_constructible_v<Ext, decltype(arr1)>); | ||
| static_assert(is_nothrow_constructible_v<Ext, decltype(s1)>); | ||
|
|
||
| array<ConvertibleToInt<int>, 2> arr2; | ||
| Ext ext2a{arr2}; | ||
| span s2{arr2}; | ||
| Ext ext2b{s2}; | ||
| assert(ext2a == ext2b); | ||
| static_assert(is_nothrow_constructible_v<Ext, decltype(arr2)>); | ||
| static_assert(is_nothrow_constructible_v<Ext, decltype(s2)>); | ||
|
|
||
| static_assert(!is_constructible_v<Ext, array<NonConvertibleToAnything, 2>>); | ||
| static_assert(!is_constructible_v<Ext, span<NonConvertibleToAnything, 2>>); | ||
| } | ||
|
|
||
| { // Check construction from arrays/spans with elements that may throw during conversion to index_type | ||
| using Ext = extents<long, dynamic_extent, dynamic_extent>; | ||
| static_assert(!is_constructible_v<Ext, array<ConvertibleToInt<int, IsNothrow::no>, 2>>); | ||
| static_assert(!is_constructible_v<Ext, span<ConvertibleToInt<int, IsNothrow::no>, 2>>); | ||
| } | ||
|
|
||
| { // Check construction from arrays/spans with invalid size | ||
| using Ext = extents<short, 5, 5>; | ||
| static_assert(!is_constructible_v<Ext, array<int, 1>>); | ||
| static_assert(!is_constructible_v<Ext, array<int, 3>>); | ||
| static_assert(!is_constructible_v<Ext, span<int, 1>>); | ||
| static_assert(!is_constructible_v<Ext, span<int, 3>>); | ||
| static_assert(!is_constructible_v<Ext, span<int>>); | ||
| static_assert(!is_constructible_v<Ext, span<int>>); | ||
| } | ||
|
|
||
| { // Check implicit conversions | ||
| static_assert(!NotImplicitlyConstructibleFrom<extents<signed char, 3, dynamic_extent>, array<int, 1>>); | ||
| static_assert(NotImplicitlyConstructibleFrom<extents<signed char, 3, dynamic_extent>, array<int, 2>>); | ||
| static_assert(!NotImplicitlyConstructibleFrom<extents<signed char, 3, dynamic_extent>, span<int, 1>>); | ||
| static_assert(NotImplicitlyConstructibleFrom<extents<signed char, 3, dynamic_extent>, span<int, 2>>); | ||
| } | ||
| } | ||
|
|
||
| constexpr void check_equality_operator() { | ||
| { // All extents are static | ||
| extents<int, 3, 3> e1; | ||
| extents<long, 2, 3> e2; | ||
| extents<size_t, 3, 3> e3; | ||
| assert(e1 != e2); | ||
| assert(e2 != e3); | ||
| assert(e1 == e3); | ||
| } | ||
|
|
||
| { // Some extents are static, some dynamic | ||
| extents<int, 3, dynamic_extent> e1{1}; | ||
| extents<long, dynamic_extent, 3> e2{2}; | ||
| extents<size_t, 2, dynamic_extent> e3{3}; | ||
| assert(e1 != e2); | ||
| assert(e2 == e3); | ||
| assert(e1 != e2); | ||
| } | ||
|
|
||
| { // All extents are dynamic | ||
| dextents<int, 2> e1{1, 2}; | ||
| dextents<long, 2> e2{1, 2}; | ||
| dextents<size_t, 2> e3{1, 3}; | ||
| assert(e1 == e2); | ||
| assert(e2 != e3); | ||
| assert(e1 != e3); | ||
| } | ||
| } | ||
|
|
||
| constexpr bool test() { | ||
| // check_members<short>(); // FIXME Definitely a bug. | ||
| check_members<int, 1, 2, 3>(); | ||
| check_members<unsigned long long, dynamic_extent, 4, 5>(); | ||
| // check_members<short, dynamic_extent, dynamic_extent, 6>(); // FIXME Bug in array/span constructor? | ||
| check_members<unsigned char, dynamic_extent, dynamic_extent, dynamic_extent>(); | ||
| check_construction_from_other_extents(); | ||
| check_construction_from_extents_pack(); | ||
| check_construction_from_array_and_span(); | ||
| check_equality_operator(); | ||
| return true; | ||
| } | ||
|
|
||
| template <class T, size_t ExpectedRank> | ||
| constexpr bool all_extents_dynamic = false; | ||
|
|
||
| template <class IndexType, size_t... Extents, size_t ExpectedRank> | ||
| constexpr bool all_extents_dynamic<extents<IndexType, Extents...>, ExpectedRank> = | ||
| ((Extents == dynamic_extent) && ...) && (sizeof...(Extents) == ExpectedRank); | ||
|
|
||
| template <class... Args> | ||
| concept CanDeduceExtents = requires(Args&&... args) { extents{forward<Args>(args)...}; }; | ||
|
|
||
| // Check deduction guide | ||
| using DG = decltype(extents{'1', 2, 3u, 4ll, ConvertibleToInt<size_t>{}}); | ||
| static_assert(all_extents_dynamic<DG, 5>); | ||
| static_assert(same_as<DG::index_type, size_t>); | ||
| static_assert(!CanDeduceExtents<int, long, short, NonConvertibleToAnything>); | ||
|
|
||
| // Check dextents | ||
| static_assert(all_extents_dynamic<dextents<signed char, 0>, 0>); | ||
| static_assert(all_extents_dynamic<dextents<unsigned short, 2>, 2>); | ||
| static_assert(all_extents_dynamic<dextents<int, 3>, 3>); | ||
| static_assert(all_extents_dynamic<dextents<unsigned long, 5>, 5>); | ||
|
|
||
| int main() { | ||
| static_assert(test()); | ||
| test(); | ||
| } | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.