diff --git a/stl/inc/mdspan b/stl/inc/mdspan index 5bc6c74f0f1..adbe8e48913 100644 --- a/stl/inc/mdspan +++ b/stl/inc/mdspan @@ -13,6 +13,7 @@ _EMIT_STL_WARNING(STL4038, "The contents of are available only with C++ #else // ^^^ not supported / supported language mode vvv #include #include +#include #pragma pack(push, _CRT_PACKING) #pragma warning(push, _STL_WARNING_LEVEL) @@ -201,7 +202,7 @@ public: } for (size_t _Dim = 0; _Dim < sizeof...(_Extents); ++_Dim) { - if (_Left.extent(_Dim) != _Right.extent(_Dim)) { + if (_STD cmp_not_equal(_Left.extent(_Dim), _Right.extent(_Dim))) { return false; } } diff --git a/tests/std/test.lst b/tests/std/test.lst index a70c5617cb2..b6b81ee1106 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -228,6 +228,8 @@ tests\LWG3480_directory_iterator_range tests\LWG3545_pointer_traits_sfinae tests\LWG3610_iota_view_size_and_integer_class tests\P0009R18_mdspan +tests\P0009R18_mdspan_default_accessor +tests\P0009R18_mdspan_extents tests\P0019R8_atomic_ref tests\P0024R2_parallel_algorithms_adjacent_difference tests\P0024R2_parallel_algorithms_adjacent_find diff --git a/tests/std/tests/P0009R18_mdspan_default_accessor/env.lst b/tests/std/tests/P0009R18_mdspan_default_accessor/env.lst new file mode 100644 index 00000000000..18e2d7c71ec --- /dev/null +++ b/tests/std/tests/P0009R18_mdspan_default_accessor/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\concepts_latest_matrix.lst diff --git a/tests/std/tests/P0009R18_mdspan_default_accessor/test.cpp b/tests/std/tests/P0009R18_mdspan_default_accessor/test.cpp new file mode 100644 index 00000000000..21379295e76 --- /dev/null +++ b/tests/std/tests/P0009R18_mdspan_default_accessor/test.cpp @@ -0,0 +1,66 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +template +constexpr void test_one(array elems) { + using Accessor = default_accessor; + + // Check modeled concepts + static_assert(is_nothrow_move_constructible_v); + static_assert(is_nothrow_move_assignable_v); + static_assert(is_nothrow_swappable_v); + static_assert(is_trivially_copyable_v); + static_assert(semiregular); + + // Check nested types + static_assert(same_as); + static_assert(same_as); + static_assert(same_as); + static_assert(same_as); + + // Check default constructor + Accessor accessor; + static_assert(is_nothrow_default_constructible_v); + + { // Check converting constructor from other accessor + [[maybe_unused]] default_accessor const_accessor = accessor; + static_assert(is_nothrow_constructible_v, Accessor>); + static_assert(!is_constructible_v>); + } + + { // Check 'access' member function + same_as 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 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({'a', 'b', 'c'}); + test_one({1, 2, 3}); + test_one({1.1, 2.2, 3.3}); + test_one({L"1", L"2", L"3"}); + test_one({3, 2, 1}); + return true; +} + +int main() { + static_assert(test()); + test(); +} diff --git a/tests/std/tests/P0009R18_mdspan_extents/env.lst b/tests/std/tests/P0009R18_mdspan_extents/env.lst new file mode 100644 index 00000000000..18e2d7c71ec --- /dev/null +++ b/tests/std/tests/P0009R18_mdspan_extents/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\concepts_latest_matrix.lst diff --git a/tests/std/tests/P0009R18_mdspan_extents/test.cpp b/tests/std/tests/P0009R18_mdspan_extents/test.cpp new file mode 100644 index 00000000000..b73415b842d --- /dev/null +++ b/tests/std/tests/P0009R18_mdspan_extents/test.cpp @@ -0,0 +1,295 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +enum class IsNothrow : bool { no, yes }; + +template +struct ConvertibleToInt { + constexpr operator Int() const noexcept(to_underlying(Nothrow)) { + return Int{1}; + } +}; + +struct NonConvertibleToAnything {}; + +template +constexpr void check_implicit_conversion(T); // not defined + +// clang-format off +template +concept NotImplicitlyConstructibleFrom = + constructible_from + && !requires(Args&&... args) { check_implicit_conversion({forward(args)...}); }; +// clang-format on + +template +constexpr void do_check_members(index_sequence) { + using Ext = extents; + + // Each specialization of extents models regular and is trivially copyable + static_assert(regular); + static_assert(is_trivially_copyable_v); + + // Check member types + static_assert(same_as); + static_assert(same_as>); + static_assert(same_as); + + // 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); + + // Check 'extent' observer + assert((((ext.extent(Indices) == Extents && Extents != dynamic_extent) || ext.extent(Indices) == 0) && ...)); + + using OtherIndexType = conditional_t, long long, unsigned long long>; + using Ext2 = 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); + // 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); + // Other tests are defined in 'check_construction_from_extents_pack' function + } + + { // Check construction from array and span + auto arr = to_array({ext.extent(Indices)...}); + Ext2 ext2a{arr}; + assert(((ext.extent(Indices) == ext2a.extent(Indices)) && ...)); + assert(ext == ext2a); + static_assert(is_nothrow_constructible_v); + + span s{arr}; + Ext2 ext2b{s}; + assert(((ext.extent(Indices) == ext2b.extent(Indices)) && ...)); + assert(ext == ext2b); + static_assert(is_nothrow_constructible_v); + // Other tests are defined in 'check_construction_from_array_and_span' function + } +} + +template +constexpr void check_members() { + do_check_members(make_index_sequence{}); +} + +constexpr void check_construction_from_other_extents() { + { // Check construction from too big or too small other extents + using Ext = extents; + static_assert(!is_constructible_v); + static_assert(!is_constructible_v>); + } + + { // Check construction with different values + static_assert(is_nothrow_constructible_v, extents>); + static_assert(is_nothrow_constructible_v, extents>); + static_assert(is_nothrow_constructible_v, extents>); + static_assert(is_nothrow_constructible_v, extents>); + static_assert(!is_constructible_v, extents>); + } + + { // Check postconditions + extents ext{4, 4}; + extents ext2{ext}; + assert(ext == ext2); + assert(ext2.extent(0) == 4); + assert(ext2.extent(1) == 4); + + extents ext3{ext}; + assert(ext == ext3); + assert(ext3.extent(0) == 4); + assert(ext3.extent(1) == 4); + } + + { // Check implicit conversions + static_assert(!NotImplicitlyConstructibleFrom, extents>); + static_assert(NotImplicitlyConstructibleFrom, extents>); + static_assert(NotImplicitlyConstructibleFrom, extents>); + static_assert(NotImplicitlyConstructibleFrom, extents>); + } +} + +constexpr void check_construction_from_extents_pack() { + { // Check construction from various types + using Ext = extents; + static_assert(is_nothrow_constructible_v); + static_assert(!is_constructible_v); + static_assert(is_nothrow_constructible_v); + } + + { // Check construction from types (not) convertible to index_type + using Ext = extents; + static_assert(is_nothrow_constructible_v>); + static_assert(!is_constructible_v); + static_assert(is_nothrow_constructible_v>); + static_assert(!is_constructible_v); + } + + { // Check construction from types that may throw during conversion to index_type + using Ext = extents; + static_assert(!is_constructible_v>); + static_assert(!is_constructible_v>); + } + +#if 0 // FIXME Bug in array/span constructor? + { // Check postconditions [FIXME] + using Ext = extents; + array arr = {4, 4, 4}; + Ext ext{arr}; + Ext ext2{4, 4, 4}; + assert(ext == ext2); + } +#endif // Bug? + + { // Check implicit conversions + static_assert(NotImplicitlyConstructibleFrom, unsigned long long>); + static_assert(NotImplicitlyConstructibleFrom, long, long>); + static_assert(NotImplicitlyConstructibleFrom, 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; + + array arr1 = {4, 5}; + Ext ext1a{arr1}; + span s1{arr1}; + Ext ext1b{s1}; + assert(ext1a == ext1b); + static_assert(is_nothrow_constructible_v); + static_assert(is_nothrow_constructible_v); + + array, 2> arr2; + Ext ext2a{arr2}; + span s2{arr2}; + Ext ext2b{s2}; + assert(ext2a == ext2b); + static_assert(is_nothrow_constructible_v); + static_assert(is_nothrow_constructible_v); + + static_assert(!is_constructible_v>); + static_assert(!is_constructible_v>); + } + + { // Check construction from arrays/spans with elements that may throw during conversion to index_type + using Ext = extents; + static_assert(!is_constructible_v, 2>>); + static_assert(!is_constructible_v, 2>>); + } + + { // Check construction from arrays/spans with invalid size + using Ext = extents; + static_assert(!is_constructible_v>); + static_assert(!is_constructible_v>); + static_assert(!is_constructible_v>); + static_assert(!is_constructible_v>); + static_assert(!is_constructible_v>); + static_assert(!is_constructible_v>); + } + + { // Check implicit conversions + static_assert(!NotImplicitlyConstructibleFrom, array>); + static_assert(NotImplicitlyConstructibleFrom, array>); + static_assert(!NotImplicitlyConstructibleFrom, span>); + static_assert(NotImplicitlyConstructibleFrom, span>); + } +} + +constexpr void check_equality_operator() { + { // All extents are static + extents e1; + extents e2; + extents e3; + assert(e1 != e2); + assert(e2 != e3); + assert(e1 == e3); + } + + { // Some extents are static, some dynamic + extents e1{1}; + extents e2{2}; + extents e3{3}; + assert(e1 != e2); + assert(e2 == e3); + assert(e1 != e2); + } + + { // All extents are dynamic + dextents e1{1, 2}; + dextents e2{1, 2}; + dextents e3{1, 3}; + assert(e1 == e2); + assert(e2 != e3); + assert(e1 != e3); + } +} + +constexpr bool test() { + // check_members(); // FIXME Definitely a bug. + check_members(); + check_members(); + // check_members(); // FIXME Bug in array/span constructor? + check_members(); + check_construction_from_other_extents(); + check_construction_from_extents_pack(); + check_construction_from_array_and_span(); + check_equality_operator(); + return true; +} + +template +constexpr bool all_extents_dynamic = false; + +template +constexpr bool all_extents_dynamic, ExpectedRank> = + ((Extents == dynamic_extent) && ...) && (sizeof...(Extents) == ExpectedRank); + +template +concept CanDeduceExtents = requires(Args&&... args) { extents{forward(args)...}; }; + +// Check deduction guide +using DG = decltype(extents{'1', 2, 3u, 4ll, ConvertibleToInt{}}); +static_assert(all_extents_dynamic); +static_assert(same_as); +static_assert(!CanDeduceExtents); + +// Check dextents +static_assert(all_extents_dynamic, 0>); +static_assert(all_extents_dynamic, 2>); +static_assert(all_extents_dynamic, 3>); +static_assert(all_extents_dynamic, 5>); + +int main() { + static_assert(test()); + test(); +}