Index: libcxx/docs/FeatureTestMacroTable.rst =================================================================== --- libcxx/docs/FeatureTestMacroTable.rst +++ libcxx/docs/FeatureTestMacroTable.rst @@ -332,7 +332,7 @@ --------------------------------------------------- ----------------- ``__cpp_lib_is_scoped_enum`` ``202011L`` --------------------------------------------------- ----------------- - ``__cpp_lib_mdspan`` *unimplemented* + ``__cpp_lib_mdspan`` ``202207L`` --------------------------------------------------- ----------------- ``__cpp_lib_move_only_function`` *unimplemented* --------------------------------------------------- ----------------- Index: libcxx/docs/Status/Cxx23.rst =================================================================== --- libcxx/docs/Status/Cxx23.rst +++ libcxx/docs/Status/Cxx23.rst @@ -40,7 +40,6 @@ .. note:: - .. [#note-P0009R18] P0009R18: ``extents``, ``dextents``, ``layout_left``, ``layout_right``, and ``default_accessor`` are implemented. .. [#note-P0533R9] P0533R9: ``isfinite``, ``isinf``, ``isnan`` and ``isnormal`` are implemented. .. [#note-P1413R3] P1413R3: ``std::aligned_storage_t`` and ``std::aligned_union_t`` are marked deprecated, but clang doesn't issue a diagnostic for deprecated using template declarations. Index: libcxx/docs/Status/Cxx23Papers.csv =================================================================== --- libcxx/docs/Status/Cxx23Papers.csv +++ libcxx/docs/Status/Cxx23Papers.csv @@ -51,7 +51,7 @@ "`P2442R1 `__","LWG","Windowing range adaptors: ``views::chunk`` and ``views::slide``","February 2022","","","|ranges|" "`P2443R1 `__","LWG","``views::chunk_by``","February 2022","","","|ranges|" "","","","","","","" -"`P0009R18 `__","LWG","mdspan: A Non-Owning Multidimensional Array Reference","July 2022","|In progress| [#note-P0009R18]_|","" +"`P0009R18 `__","LWG","mdspan: A Non-Owning Multidimensional Array Reference","July 2022","|Complete|","" "`P0429R9 `__","LWG","A Standard ``flat_map``","July 2022","","" "`P1169R4 `__","LWG","``static operator()``","July 2022","|Complete|","16.0" "`P1222R4 `__","LWG","A Standard ``flat_set``","July 2022","","" Index: libcxx/include/CMakeLists.txt =================================================================== --- libcxx/include/CMakeLists.txt +++ libcxx/include/CMakeLists.txt @@ -505,6 +505,7 @@ __mdspan/extents.h __mdspan/layout_left.h __mdspan/layout_right.h + __mdspan/layout_stride.h __mdspan/mdspan.h __memory/addressof.h __memory/align.h Index: libcxx/include/__fwd/mdspan.h =================================================================== --- libcxx/include/__fwd/mdspan.h +++ libcxx/include/__fwd/mdspan.h @@ -42,14 +42,11 @@ class mapping; }; -/* -// Will be implemented with follow on revision // Layout policy with a unique mapping where strides are arbitrary struct layout_stride { - template - class mapping; + template + class mapping; }; -*/ #endif // _LIBCPP_STD_VER >= 23 Index: libcxx/include/__mdspan/layout_stride.h =================================================================== --- /dev/null +++ libcxx/include/__mdspan/layout_stride.h @@ -0,0 +1,347 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// Kokkos v. 4.0 +// Copyright (2022) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). +// +// Under the terms of Contract DE-NA0003525 with NTESS, +// the U.S. Government retains certain rights in this software. +// +//===---------------------------------------------------------------------===// + +#ifndef _LIBCPP___MDSPAN_LAYOUT_STRIDE_H +#define _LIBCPP___MDSPAN_LAYOUT_STRIDE_H + +#include <__assert> +#include <__config> +#include <__fwd/mdspan.h> +#include <__mdspan/extents.h> +#include <__type_traits/is_constructible.h> +#include <__type_traits/is_convertible.h> +#include <__type_traits/is_nothrow_constructible.h> +#include <__utility/as_const.h> +#include <__utility/integer_sequence.h> +#include +#include +#include +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 23 + +namespace __mdspan_detail { +template +constexpr bool __is_mapping_of = + is_same_v, _Mapping>; + +template +concept __layout_mapping_alike = requires { + requires __is_mapping_of; + requires __is_extents_v; + { _Mapping::is_always_strided() } -> same_as; + { _Mapping::is_always_exhaustive() } -> same_as; + { _Mapping::is_always_unique() } -> same_as; + bool_constant<_Mapping::is_always_strided()>::value; + bool_constant<_Mapping::is_always_exhaustive()>::value; + bool_constant<_Mapping::is_always_unique()>::value; +}; +} // namespace __mdspan_detail + +template +class layout_stride::mapping { +public: + static_assert(__mdspan_detail::__is_extents<_Extents>::value, + "layout_stride::mapping template argument must be a specialization of extents."); + + using extents_type = _Extents; + using index_type = typename extents_type::index_type; + using size_type = typename extents_type::size_type; + using rank_type = typename extents_type::rank_type; + using layout_type = layout_stride; + +private: + static constexpr rank_type __rank_ = extents_type::rank(); + + // Used for default construction check and mandates + _LIBCPP_HIDE_FROM_ABI static constexpr bool __required_span_size_is_representable(const extents_type& __ext) { + if constexpr (__rank_ == 0) + return true; + + index_type __prod = __ext.extent(0); + for (rank_type __r = 1; __r < __rank_; __r++) { + bool __overflowed = __builtin_mul_overflow(__prod, __ext.extent(__r), &__prod); + if (__overflowed) + return false; + } + return true; + } + + template + _LIBCPP_HIDE_FROM_ABI static constexpr bool + __required_span_size_is_representable(const extents_type& __ext, span<_OtherIndexType, __rank_> __strides) { + if constexpr (__rank_ == 0) + return true; + + index_type __size = 1; + for (rank_type __r = 0; __r < __rank_; __r++) { + // We can only check correct conversion of _OtherIndexType if it is an integral + if constexpr (is_integral_v<_OtherIndexType>) { + using _CommonType = common_type_t; + if (static_cast<_CommonType>(__strides[__r]) > static_cast<_CommonType>(std::numeric_limits::max())) + return false; + } + if (__ext.extent(__r) == static_cast(0)) + return true; + index_type __prod = (__ext.extent(__r) - 1); + bool __overflowed_mul = __builtin_mul_overflow(__prod, static_cast(__strides[__r]), &__prod); + if (__overflowed_mul) + return false; + bool __overflowed_add = __builtin_add_overflow(__size, __prod, &__size); + if (__overflowed_add) + return false; + } + return true; + } + + static_assert((extents_type::rank_dynamic() > 0) || __required_span_size_is_representable(extents_type()), + "layout_stride::mapping product of static extents must be representable as index_type."); + +public: + // [mdspan.layout.stride.cons], constructors + _LIBCPP_HIDE_FROM_ABI constexpr mapping() noexcept : __extents_(extents_type()) { + // Note the nominal precondition is covered by above static assert since + // if rank_dynamic is != 0 required_span_size is zero for default construction + if constexpr (__rank_ > 0) { + index_type __stride = 1; + for (rank_type __r = __rank_ - 1; __r > static_cast(0); __r--) { + __strides_[__r] = __stride; + __stride *= __extents_.extent(__r); + } + __strides_[0] = __stride; + } + } + + _LIBCPP_HIDE_FROM_ABI constexpr mapping(const mapping&) noexcept = default; + + template + requires(is_convertible_v && + is_nothrow_constructible_v) + _LIBCPP_HIDE_FROM_ABI constexpr mapping(const extents_type& __ext, span<_OtherIndexType, __rank_> __strides) noexcept + : __extents_(__ext), __strides_([&](index_sequence<_Pos...>) { + return __mdspan_detail::__possibly_empty_array{ + static_cast(std::as_const(__strides[_Pos]))...}; + }(make_index_sequence<__rank_>())) { + _LIBCPP_ASSERT(([&](index_sequence<_Pos...>) { + // For integrals we can do a pre-conversion check, for other types not + if constexpr (is_integral_v<_OtherIndexType>) { + return ((__strides[_Pos] > static_cast<_OtherIndexType>(0)) && ... && true); + } else { + return ((static_cast(__strides[_Pos]) > static_cast(0)) && ... && true); + } + }(make_index_sequence<__rank_>())), + "layout_stride::mapping ctor: all strides must be greater than 0"); + _LIBCPP_ASSERT(__required_span_size_is_representable(__ext, __strides), + "layout_stride::mapping ctor: required span size is not representable as index_type."); + if constexpr (__rank_ > 1) { + _LIBCPP_ASSERT( + ([&](index_sequence<_Pos...>) { + // basically sort the dimensions based on strides and extents, sorting is represented in permute array + std::array __permute{_Pos...}; + for (rank_type __i = __rank_ - 1; __i > 0; __i--) { + for (rank_type __r = 0; __r < __i; __r++) + if (static_cast(__strides[__permute[__r]]) > + static_cast(__strides[__permute[__r + 1]])) { + swap(__permute[__r], __permute[__r + 1]); + } else { + // if two strides are the same then one of the extents must be 1 or 0 + // both could be, but you can't have one larger than 1 come first + if ((static_cast(__strides[__permute[__r]]) == + static_cast(__strides[__permute[__r + 1]])) && + (__ext.extent(__permute[__r]) > 1)) + swap(__permute[__r], __permute[__r + 1]); + } + } + // check that this permutations represents a growing set + for (rank_type __i = 1; __i < __rank_; __i++) + if (static_cast(__strides[__permute[__i]]) < + static_cast(__strides[__permute[__i - 1]]) * __extents_.extent(__permute[__i - 1])) + return false; + return true; + }(make_index_sequence<__rank_>())), + "layout_stride::mapping ctor: the provided extents and strides lead to a non-unique mapping"); + } + } + + template + requires(is_convertible_v && + is_nothrow_constructible_v) + _LIBCPP_HIDE_FROM_ABI constexpr mapping(const extents_type& __ext, + const array<_OtherIndexType, __rank_>& __strides) noexcept + : mapping(__ext, span(__strides)){}; + + template + requires(__mdspan_detail::__layout_mapping_alike<_StridedLayoutMapping> && + is_constructible_v && + _StridedLayoutMapping::is_always_unique() && _StridedLayoutMapping::is_always_strided()) + _LIBCPP_HIDE_FROM_ABI constexpr explicit( + !(is_convertible_v && + (__mdspan_detail::__is_mapping_of || + __mdspan_detail::__is_mapping_of || + __mdspan_detail::__is_mapping_of))) + mapping(const _StridedLayoutMapping& __other) noexcept + : __extents_(__other.extents()), __strides_([&](index_sequence<_Pos...>) { + // stride() only compiles for rank > 0 + if constexpr (__rank_ > 0) { + return __mdspan_detail::__possibly_empty_array{ + static_cast(__other.stride(_Pos))...}; + } else { + return __mdspan_detail::__possibly_empty_array{}; + } + }(make_index_sequence<__rank_>())) { + // stride() only compiles for rank > 0 + if constexpr (__rank_ > 0) { + _LIBCPP_ASSERT( + ([&](index_sequence<_Pos...>) { + return ((static_cast(__other.stride(_Pos)) > static_cast(0)) && ... && true); + }(make_index_sequence<__rank_>())), + "layout_stride::mapping converting ctor: all strides must be greater than 0"); + } + _LIBCPP_ASSERT( + __mdspan_detail::__is_representable_as(__other.required_span_size()), + "layout_stride::mapping converting ctor: other.required_span_size() must be representable as index_type."); + _LIBCPP_ASSERT(([&](index_sequence<_Pos...>) { + return static_cast(0) == static_cast(__other((_Pos ? 0 : 0)...)); + }(make_index_sequence<__rank_>())), + "layout_stride::mapping converting ctor: base offset of mapping must be zero."); + } + + _LIBCPP_HIDE_FROM_ABI constexpr mapping& operator=(const mapping&) noexcept = default; + + // [mdspan.layout.stride.obs], observers + _LIBCPP_HIDE_FROM_ABI constexpr const extents_type& extents() const noexcept { return __extents_; } + + _LIBCPP_HIDE_FROM_ABI constexpr array strides() const noexcept { + return [&](index_sequence<_Pos...>) { + return array{__strides_[_Pos]...}; + }(make_index_sequence<__rank_>()); + } + + _LIBCPP_HIDE_FROM_ABI constexpr index_type required_span_size() const noexcept { + if constexpr (__rank_ == 0) { + return static_cast(1); + } else { + return [&](index_sequence<_Pos...>) { + if ((__extents_.extent(_Pos) * ... * 1) == 0) + return static_cast(0); + else + return static_cast( + static_cast(1) + + (((__extents_.extent(_Pos) - static_cast(1)) * __strides_[_Pos]) + ... + + static_cast(0))); + }(make_index_sequence<__rank_>()); + } + } + + template + requires((sizeof...(_Indices) == __rank_) && (is_convertible_v<_Indices, index_type> && ...) && + (is_nothrow_constructible_v && ...)) + _LIBCPP_HIDE_FROM_ABI constexpr index_type operator()(_Indices... __idx) const noexcept { + // Mappings are generally meant to be used for accessing allocations and are meant to guarantee to never + // return a value exceeding required_span_size(), which is used to know how large an allocation one needs + // Thus, this is a canonical point in multi-dimensional data structures to make invalid element access checks + // However, mdspan does check this on its own, so for now we avoid double checking in hardened mode + _LIBCPP_ASSERT(__mdspan_detail::__is_multidimensional_index_in(__extents_, __idx...), + "layout_stride::mapping: out of bounds indexing"); + return [&](index_sequence<_Pos...>) { + return ((static_cast(__idx) * __strides_[_Pos]) + ... + index_type(0)); + }(make_index_sequence()); + } + + _LIBCPP_HIDE_FROM_ABI static constexpr bool is_always_unique() noexcept { return true; } + _LIBCPP_HIDE_FROM_ABI static constexpr bool is_always_exhaustive() noexcept { return false; } + _LIBCPP_HIDE_FROM_ABI static constexpr bool is_always_strided() noexcept { return true; } + + _LIBCPP_HIDE_FROM_ABI static constexpr bool is_unique() noexcept { return true; } + // The answer of this function is fairly complex in the case where one or more + // extents are zero. + // Technically its meaningless to query is_exhaustive() in that case, but unfortunately + // the way the standard defines this function, we can't give a simple true or false then. + _LIBCPP_HIDE_FROM_ABI constexpr bool is_exhaustive() const noexcept { + if constexpr (__rank_ == 0) + return true; + else { + index_type __span_size = required_span_size(); + if (__span_size == static_cast(0)) { + if constexpr (__rank_ == 1) + return true; + else { + rank_type __r_largest = 0; + for (rank_type __r = 1; __r < __rank_; __r++) + if (__strides_[__r] > __strides_[__r_largest]) + __r_largest = __r; + for (rank_type __r = 0; __r < __rank_; __r++) + if (__extents_.extent(__r) == 0 && __r != __r_largest) + return false; + return true; + } + } else { + return required_span_size() == [&](index_sequence<_Pos...>) { + return (__extents_.extent(_Pos) * ... * static_cast(1)); + }(make_index_sequence<__rank_>()); + } + } + } + _LIBCPP_HIDE_FROM_ABI static constexpr bool is_strided() noexcept { return true; } + + _LIBCPP_HIDE_FROM_ABI constexpr index_type stride(rank_type __r) const noexcept + requires(__rank_ > 0) + { + _LIBCPP_ASSERT(__r < __rank_, "layout_stride::mapping::stride(): invalid rank index"); + return __strides_[__r]; + } + + template + requires(__mdspan_detail::__layout_mapping_alike<_OtherMapping> && + (_OtherMapping::extents_type::rank() == __rank_) && _OtherMapping::is_always_strided()) + _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const mapping& __lhs, const _OtherMapping& __rhs) noexcept { + if (([&](index_sequence<_Pos...>) { + return static_cast(__rhs((_Pos ? 0 : 0)...)); + }(make_index_sequence<__rank_>())) != static_cast(0)) + return false; + if constexpr (__rank_ == 0) + return true; + else { + return __lhs.extents() == __rhs.extents() && [&](index_sequence<_Pos...>) { + // avoid warning when comparing signed and unsigner integers and pick the wider of two types + using _CommonType = common_type_t; + return ((static_cast<_CommonType>(__lhs.stride(_Pos)) == static_cast<_CommonType>(__rhs.stride(_Pos))) && ... && + true); + }(make_index_sequence<__rank_>()); + } + } + +private: + _LIBCPP_NO_UNIQUE_ADDRESS extents_type __extents_{}; + _LIBCPP_NO_UNIQUE_ADDRESS __mdspan_detail::__possibly_empty_array __strides_{}; +}; + +#endif // _LIBCPP_STD_VER >= 23 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___MDSPAN_LAYOUT_STRIDE_H Index: libcxx/include/mdspan =================================================================== --- libcxx/include/mdspan +++ libcxx/include/mdspan @@ -190,6 +190,63 @@ }; } +// layout_stride synopsis + +namespace std { + template + class layout_stride::mapping { + public: + using extents_type = Extents; + using index_type = typename extents_type::index_type; + using size_type = typename extents_type::size_type; + using rank_type = typename extents_type::rank_type; + using layout_type = layout_stride; + + private: + static constexpr rank_type rank_ = extents_type::rank(); // exposition only + + public: + // [mdspan.layout.stride.cons], constructors + constexpr mapping() noexcept; + constexpr mapping(const mapping&) noexcept = default; + template + constexpr mapping(const extents_type&, span) noexcept; + template + constexpr mapping(const extents_type&, const array&) noexcept; + + template + constexpr explicit(see below) mapping(const StridedLayoutMapping&) noexcept; + + constexpr mapping& operator=(const mapping&) noexcept = default; + + // [mdspan.layout.stride.obs], observers + constexpr const extents_type& extents() const noexcept { return extents_; } + constexpr array strides() const noexcept { return strides_; } + + constexpr index_type required_span_size() const noexcept; + + template + constexpr index_type operator()(Indices...) const noexcept; + + static constexpr bool is_always_unique() noexcept { return true; } + static constexpr bool is_always_exhaustive() noexcept { return false; } + static constexpr bool is_always_strided() noexcept { return true; } + + static constexpr bool is_unique() noexcept { return true; } + constexpr bool is_exhaustive() const noexcept; + static constexpr bool is_strided() noexcept { return true; } + + constexpr index_type stride(rank_type i) const noexcept { return strides_[i]; } + + template + friend constexpr bool operator==(const mapping&, const OtherMapping&) noexcept; + + private: + extents_type extents_{}; // exposition only + array strides_{}; // exposition only + }; +} + // default_accessor synopsis namespace std { @@ -348,7 +405,9 @@ #include <__mdspan/extents.h> #include <__mdspan/layout_left.h> #include <__mdspan/layout_right.h> +#include <__mdspan/layout_stride.h> #include <__mdspan/mdspan.h> +#include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header Index: libcxx/include/version =================================================================== --- libcxx/include/version +++ libcxx/include/version @@ -426,7 +426,7 @@ # define __cpp_lib_forward_like 202207L # define __cpp_lib_invoke_r 202106L # define __cpp_lib_is_scoped_enum 202011L -// # define __cpp_lib_mdspan 202207L +# define __cpp_lib_mdspan 202207L // # define __cpp_lib_move_only_function 202110L # undef __cpp_lib_optional # define __cpp_lib_optional 202110L Index: libcxx/test/libcxx/containers/views/mdspan/layout_stride/assert.conversion.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/libcxx/containers/views/mdspan/layout_stride/assert.conversion.pass.cpp @@ -0,0 +1,95 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// REQUIRES: has-unix-headers +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 +// UNSUPPORTED: libcpp-hardening-mode=unchecked +// XFAIL: availability-verbose_abort-missing + +// + +// template +// constexpr explicit(see below) +// mapping(const StridedLayoutMapping& other) noexcept; +// +// Constraints: +// - layout-mapping-alike is satisfied. +// - is_constructible_v is true. +// - StridedLayoutMapping::is_always_unique() is true. +// - StridedLayoutMapping::is_always_strided() is true. +// +// Preconditions: +// - StridedLayoutMapping meets the layout mapping requirements ([mdspan.layout.policy.reqmts]), +// - other.stride(r) > 0 is true for every rank index r of extents(), +// - other.required_span_size() is representable as a value of type index_type ([basic.fundamental]), and +// - OFFSET(other) == 0 is true. +// +// Effects: Direct-non-list-initializes extents_ with other.extents(), and for all d in the range [0, rank_), +// direct-non-list-initializes strides_[d] with other.stride(d). +// +// Remarks: The expression inside explicit is equivalent to: +// - !(is_convertible_v && +// (is-mapping-of || +// is-mapping-of || +// is-mapping-of)) + +#include +#include + +#include "check_assertion.h" +#include "../../../../../std/containers/views/mdspan/CustomTestLayouts.h" + +int main(int, char**) { + constexpr size_t D = std::dynamic_extent; + + // working case + { + std::extents arg_exts{100, 5}; + std::layout_stride::mapping> arg(arg_exts, std::array{1,100}); + [[maybe_unused]] std::layout_stride::mapping> m(arg); // should work + } + // mismatch of static extent + { + std::extents arg_exts{100, 5}; + std::layout_stride::mapping> arg(arg_exts, std::array{1,100}); + TEST_LIBCPP_ASSERT_FAILURE(([=] { std::layout_stride::mapping> m(arg); }()), + "extents construction: mismatch of provided arguments with static extents."); + } + // non-representability of extents itself + { + TEST_LIBCPP_ASSERT_FAILURE(([=] { std::layout_stride::mapping> m( + std::layout_stride::mapping>(std::extents(500), std::array{1})); }()), + "extents ctor: arguments must be representable as index_type and nonnegative"); + } + // all strides must be larger than zero + { + always_convertible_layout::mapping> offset_map(std::dextents{10,10},100,-1); + TEST_LIBCPP_ASSERT_FAILURE( + ([=] { std::layout_stride::template mapping> m(offset_map); }()), + "layout_stride::mapping converting ctor: all strides must be greater than 0"); + } + // required_span_size not representable, while individual extents are + { + std::extents arg_exts{100, 5}; + std::layout_stride::mapping> arg(arg_exts, std::array{1,100}); + // check extents would be constructible + [[maybe_unused]] std::extents e(arg_exts); + // but the product is not, so we can't use it for layout_stride + TEST_LIBCPP_ASSERT_FAILURE( + ([=] { std::layout_stride::template mapping> m(arg); }()), + "layout_stride::mapping converting ctor: other.required_span_size() must be representable as index_type."); + } + // base offset must be 0 (i.e. mapping(0,...,0)==0) for a strided layout with positiv strides + { + always_convertible_layout::mapping> offset_map(std::dextents{10,10},3); + TEST_LIBCPP_ASSERT_FAILURE( + ([=] { std::layout_stride::template mapping> m(offset_map); }()), + "layout_stride::mapping converting ctor: base offset of mapping must be zero."); + } + return 0; +} Index: libcxx/test/libcxx/containers/views/mdspan/layout_stride/assert.ctor.extents_array.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/libcxx/containers/views/mdspan/layout_stride/assert.ctor.extents_array.pass.cpp @@ -0,0 +1,83 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// REQUIRES: has-unix-headers +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 +// UNSUPPORTED: libcpp-hardening-mode=unchecked +// XFAIL: availability-verbose_abort-missing + +// + +// template +// constexpr mapping(const extents_type& e, const array& s) noexcept; +// +// Constraints: +// - is_convertible_v is true, and +// - is_nothrow_constructible_v is true. +// +// Preconditions: +// - s[i] > 0 is true for all i in the range [0, rank_). +// - REQUIRED-SPAN-SIZE(e, s) is representable as a value of type index_type ([basic.fundamental]). +// - If rank_ is greater than 0, then there exists a permutation P of the integers in the range [0, rank_), +// such that s[pi] >= s[pi_1] * e.extent(pi_1) is true for all i in the range [1, rank_), where +// pi is the ith element of P. +// [Note 1: For layout_stride, this condition is necessary and sufficient for is_unique() to be true. end note] +// +// Effects: Direct-non-list-initializes extents_ with e, and for all d in the range [0, rank_), direct-non-list-initializes strides_[d] with as_const(s[d]). + +#include +#include + +#include "check_assertion.h" + +int main(int, char**) { + constexpr size_t D = std::dynamic_extent; + + // value out of range + { + // the extents are representable but the product with strides is not, so we can't use it for layout_stride + TEST_LIBCPP_ASSERT_FAILURE( + ([=] { + std::layout_stride::template mapping> + m(std::extents(20), std::array{20, 1}); + }()), + "layout_stride::mapping ctor: required span size is not representable as index_type."); + + // check that if we first overflow in strides conversion we also fail + assert(static_cast(257u) == 1); + TEST_LIBCPP_ASSERT_FAILURE( + ([=] { + std::layout_stride::template mapping> + m(std::extents(20), std::array{257, 1}); + }()), + "layout_stride::mapping ctor: required span size is not representable as index_type."); + + // negative strides are not allowed, check with unsigned index_type so we make sure we catch that + TEST_LIBCPP_ASSERT_FAILURE( + ([=] { + std::layout_stride::template mapping> + m(std::extents(20), std::array{20, -1}); + }()), + "layout_stride::mapping ctor: all strides must be greater than 0"); + // zero strides are not allowed, check with unsigned index_type so we make sure we catch that + TEST_LIBCPP_ASSERT_FAILURE( + ([=] { + std::layout_stride::template mapping> + m(std::extents(20), std::array{20, 0}); + }()), + "layout_stride::mapping ctor: all strides must be greater than 0"); + // strides must result in unique layout + TEST_LIBCPP_ASSERT_FAILURE( + ([=] { + std::layout_stride::template mapping> + m(std::extents(20), std::array{4, 1, 200}); + }()), + "layout_stride::mapping ctor: the provided extents and strides lead to a non-unique mapping"); + } + return 0; +} Index: libcxx/test/libcxx/containers/views/mdspan/layout_stride/assert.ctor.extents_span.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/libcxx/containers/views/mdspan/layout_stride/assert.ctor.extents_span.pass.cpp @@ -0,0 +1,87 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// REQUIRES: has-unix-headers +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 +// UNSUPPORTED: libcpp-hardening-mode=unchecked +// XFAIL: availability-verbose_abort-missing + +// + +// template +// constexpr mapping(const extents_type& e, span s) noexcept; +// +// Constraints: +// - is_convertible_v is true, and +// - is_nothrow_constructible_v is true. +// +// Preconditions: +// - s[i] > 0 is true for all i in the range [0, rank_). +// - REQUIRED-SPAN-SIZE(e, s) is representable as a value of type index_type ([basic.fundamental]). +// - If rank_ is greater than 0, then there exists a permutation P of the integers in the range [0, rank_), +// such that s[pi] >= s[pi_1] * e.extent(pi_1) is true for all i in the range [1, rank_), where +// pi is the ith element of P. +// [Note 1: For layout_stride, this condition is necessary and sufficient for is_unique() to be true. end note] +// +// Effects: Direct-non-list-initializes extents_ with e, and for all d in the range [0, rank_), direct-non-list-initializes strides_[d] with as_const(s[d]). + +#include +#include + +#include "check_assertion.h" + +int main(int, char**) { + constexpr size_t D = std::dynamic_extent; + + // value out of range + { + // the extents are representable but the product with strides is not, so we can't use it for layout_stride + TEST_LIBCPP_ASSERT_FAILURE( + ([=] { + std::array strides{20, 1}; + std::layout_stride::template mapping> + m(std::extents(20), std::span(strides)); + }()), + "layout_stride::mapping ctor: required span size is not representable as index_type."); + + // check that if we first overflow in strides conversion we also fail + assert(static_cast(257u) == 1); + TEST_LIBCPP_ASSERT_FAILURE( + ([=] { + std::array strides{257, 1}; + std::layout_stride::template mapping> + m(std::extents(20), std::span(strides)); + }()), + "layout_stride::mapping ctor: required span size is not representable as index_type."); + + // negative strides are not allowed, check with unsigned index_type so we make sure we catch that + TEST_LIBCPP_ASSERT_FAILURE( + ([=] { + std::array strides{20, -1}; + std::layout_stride::template mapping> + m(std::extents(20), std::span(strides)); + }()), + "layout_stride::mapping ctor: all strides must be greater than 0"); + // zero strides are not allowed, check with unsigned index_type so we make sure we catch that + TEST_LIBCPP_ASSERT_FAILURE( + ([=] { + std::array strides{20, 0}; + std::layout_stride::template mapping> + m(std::extents(20), std::span(strides)); + }()), + "layout_stride::mapping ctor: all strides must be greater than 0"); + // strides must result in unique layout + TEST_LIBCPP_ASSERT_FAILURE( + ([=] { + std::layout_stride::template mapping> + m(std::extents(20), std::array{4, 1, 200}); + }()), + "layout_stride::mapping ctor: the provided extents and strides lead to a non-unique mapping"); + } + return 0; +} Index: libcxx/test/libcxx/containers/views/mdspan/layout_stride/assert.index_operator.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/libcxx/containers/views/mdspan/layout_stride/assert.index_operator.pass.cpp @@ -0,0 +1,84 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// REQUIRES: has-unix-headers +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 +// UNSUPPORTED: !libcpp-hardening-mode=debug +// XFAIL: availability-verbose_abort-missing + +// + +// template +// constexpr index_type operator()(Indices... i) const noexcept; +// +// Constraints: +// - sizeof...(Indices) == extents_type::rank() is true, +// - (is_convertible_v && ...) is true, and +// - (is_nothrow_constructible_v && ...) is true. +// +// Preconditions: extents_type::index-cast(i) is a multidimensional index in extents_ ([mdspan.overview]). + +#include +#include + +#include "check_assertion.h" + +int main(int, char**) { + // value out of range + { + std::layout_stride::template mapping> m; + TEST_LIBCPP_ASSERT_FAILURE(m(-1), "layout_stride::mapping: out of bounds indexing"); + TEST_LIBCPP_ASSERT_FAILURE(m(-130), "layout_stride::mapping: out of bounds indexing"); + TEST_LIBCPP_ASSERT_FAILURE(m(5), "layout_stride::mapping: out of bounds indexing"); + TEST_LIBCPP_ASSERT_FAILURE(m(1000), "layout_stride::mapping: out of bounds indexing"); + } + { + std::layout_stride::template mapping> m; + TEST_LIBCPP_ASSERT_FAILURE(m(-1), "layout_stride::mapping: out of bounds indexing"); + TEST_LIBCPP_ASSERT_FAILURE(m(-130), "layout_stride::mapping: out of bounds indexing"); + TEST_LIBCPP_ASSERT_FAILURE(m(5), "layout_stride::mapping: out of bounds indexing"); + TEST_LIBCPP_ASSERT_FAILURE(m(1000), "layout_stride::mapping: out of bounds indexing"); + } + { + std::layout_stride::template mapping> m(std::dextents(5), std::array{1}); + TEST_LIBCPP_ASSERT_FAILURE(m(-1), "layout_stride::mapping: out of bounds indexing"); + TEST_LIBCPP_ASSERT_FAILURE(m(-130), "layout_stride::mapping: out of bounds indexing"); + TEST_LIBCPP_ASSERT_FAILURE(m(5), "layout_stride::mapping: out of bounds indexing"); + TEST_LIBCPP_ASSERT_FAILURE(m(1000), "layout_stride::mapping: out of bounds indexing"); + } + { + std::layout_stride::template mapping> m(std::dextents(5), std::array{1}); + TEST_LIBCPP_ASSERT_FAILURE(m(-1), "layout_stride::mapping: out of bounds indexing"); + TEST_LIBCPP_ASSERT_FAILURE(m(-130), "layout_stride::mapping: out of bounds indexing"); + TEST_LIBCPP_ASSERT_FAILURE(m(5), "layout_stride::mapping: out of bounds indexing"); + TEST_LIBCPP_ASSERT_FAILURE(m(1000), "layout_stride::mapping: out of bounds indexing"); + } + { + std::layout_stride::template mapping> m(std::dextents(5, 7, 9), std::array{1, 10, 100}); + TEST_LIBCPP_ASSERT_FAILURE(m(-1, -1, -1), "layout_stride::mapping: out of bounds indexing"); + TEST_LIBCPP_ASSERT_FAILURE(m(-1, 0, 0), "layout_stride::mapping: out of bounds indexing"); + TEST_LIBCPP_ASSERT_FAILURE(m(0, -1, 0), "layout_stride::mapping: out of bounds indexing"); + TEST_LIBCPP_ASSERT_FAILURE(m(0, 0, -1), "layout_stride::mapping: out of bounds indexing"); + TEST_LIBCPP_ASSERT_FAILURE(m(5, 3, 3), "layout_stride::mapping: out of bounds indexing"); + TEST_LIBCPP_ASSERT_FAILURE(m(3, 7, 3), "layout_stride::mapping: out of bounds indexing"); + TEST_LIBCPP_ASSERT_FAILURE(m(3, 3, 9), "layout_stride::mapping: out of bounds indexing"); + TEST_LIBCPP_ASSERT_FAILURE(m(5, 7, 9), "layout_stride::mapping: out of bounds indexing"); + } + { + std::layout_stride::template mapping> m(std::dextents(5, 7, 9), std::array{1, 10, 100}); + TEST_LIBCPP_ASSERT_FAILURE(m(-1, -1, -1), "layout_stride::mapping: out of bounds indexing"); + TEST_LIBCPP_ASSERT_FAILURE(m(-1, 0, 0), "layout_stride::mapping: out of bounds indexing"); + TEST_LIBCPP_ASSERT_FAILURE(m(0, -1, 0), "layout_stride::mapping: out of bounds indexing"); + TEST_LIBCPP_ASSERT_FAILURE(m(0, 0, -1), "layout_stride::mapping: out of bounds indexing"); + TEST_LIBCPP_ASSERT_FAILURE(m(5, 3, 3), "layout_stride::mapping: out of bounds indexing"); + TEST_LIBCPP_ASSERT_FAILURE(m(3, 7, 3), "layout_stride::mapping: out of bounds indexing"); + TEST_LIBCPP_ASSERT_FAILURE(m(3, 3, 9), "layout_stride::mapping: out of bounds indexing"); + TEST_LIBCPP_ASSERT_FAILURE(m(5, 7, 9), "layout_stride::mapping: out of bounds indexing"); + } + return 0; +} Index: libcxx/test/libcxx/containers/views/mdspan/layout_stride/assert.stride.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/libcxx/containers/views/mdspan/layout_stride/assert.stride.pass.cpp @@ -0,0 +1,37 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// REQUIRES: has-unix-headers +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 +// UNSUPPORTED: libcpp-hardening-mode=unchecked +// XFAIL: availability-verbose_abort-missing + +// + +// constexpr index_type stride(rank_type i) const noexcept { return strides_[i]; } + + +// We intercept this inside layout_stride to give a consistent error message with +// layout_left and layout_right, technically the precondition is coming from the +// array access. + +#include +#include + +#include "check_assertion.h" + +int main(int, char**) { + // value out of range + { + std::layout_stride::template mapping> + m(std::dextents(100, 100, 100), std::array{1,100,10000}); + + TEST_LIBCPP_ASSERT_FAILURE(m.stride(4), "invalid rank index"); + } + return 0; +} Index: libcxx/test/libcxx/containers/views/mdspan/mdspan/assert.conversion.pass.cpp =================================================================== --- libcxx/test/libcxx/containers/views/mdspan/mdspan/assert.conversion.pass.cpp +++ libcxx/test/libcxx/containers/views/mdspan/mdspan/assert.conversion.pass.cpp @@ -42,7 +42,7 @@ #include #include "check_assertion.h" -#include "../../../../../std/containers/views/mdspan/mdspan/CustomTestLayouts.h" +#include "../../../../../std/containers/views/mdspan/CustomTestLayouts.h" // We use a funky mapping in this test that doesn't check the dynamic/static extents mismatch itself int main(int, char**) { Index: libcxx/test/libcxx/containers/views/mdspan/mdspan/assert.size.pass.cpp =================================================================== --- libcxx/test/libcxx/containers/views/mdspan/mdspan/assert.size.pass.cpp +++ libcxx/test/libcxx/containers/views/mdspan/mdspan/assert.size.pass.cpp @@ -22,7 +22,7 @@ #include #include "check_assertion.h" -#include "../../../../../std/containers/views/mdspan/mdspan/CustomTestLayouts.h" +#include "../../../../../std/containers/views/mdspan/CustomTestLayouts.h" // We use a funky mapping in this test where required_span_size is much smaller than the size of the index space int main(int, char**) { Index: libcxx/test/libcxx/transitive_includes/cxx03.csv =================================================================== --- libcxx/test/libcxx/transitive_includes/cxx03.csv +++ libcxx/test/libcxx/transitive_includes/cxx03.csv @@ -525,6 +525,7 @@ mdspan cstddef mdspan limits mdspan span +mdspan version memory atomic memory compare memory concepts Index: libcxx/test/libcxx/transitive_includes/cxx11.csv =================================================================== --- libcxx/test/libcxx/transitive_includes/cxx11.csv +++ libcxx/test/libcxx/transitive_includes/cxx11.csv @@ -525,6 +525,7 @@ mdspan cstddef mdspan limits mdspan span +mdspan version memory atomic memory compare memory concepts Index: libcxx/test/libcxx/transitive_includes/cxx14.csv =================================================================== --- libcxx/test/libcxx/transitive_includes/cxx14.csv +++ libcxx/test/libcxx/transitive_includes/cxx14.csv @@ -527,6 +527,7 @@ mdspan cstddef mdspan limits mdspan span +mdspan version memory atomic memory compare memory concepts Index: libcxx/test/libcxx/transitive_includes/cxx17.csv =================================================================== --- libcxx/test/libcxx/transitive_includes/cxx17.csv +++ libcxx/test/libcxx/transitive_includes/cxx17.csv @@ -527,6 +527,7 @@ mdspan cstddef mdspan limits mdspan span +mdspan version memory atomic memory compare memory concepts Index: libcxx/test/libcxx/transitive_includes/cxx20.csv =================================================================== --- libcxx/test/libcxx/transitive_includes/cxx20.csv +++ libcxx/test/libcxx/transitive_includes/cxx20.csv @@ -533,6 +533,7 @@ mdspan cstddef mdspan limits mdspan span +mdspan version memory atomic memory compare memory concepts Index: libcxx/test/libcxx/transitive_includes/cxx23.csv =================================================================== --- libcxx/test/libcxx/transitive_includes/cxx23.csv +++ libcxx/test/libcxx/transitive_includes/cxx23.csv @@ -380,6 +380,7 @@ mdspan cstddef mdspan limits mdspan span +mdspan version memory compare memory cstddef memory cstdint Index: libcxx/test/libcxx/transitive_includes/cxx26.csv =================================================================== --- libcxx/test/libcxx/transitive_includes/cxx26.csv +++ libcxx/test/libcxx/transitive_includes/cxx26.csv @@ -380,6 +380,7 @@ mdspan cstddef mdspan limits mdspan span +mdspan version memory compare memory cstddef memory cstdint Index: libcxx/test/std/containers/views/mdspan/CustomTestLayouts.h =================================================================== --- libcxx/test/std/containers/views/mdspan/CustomTestLayouts.h +++ libcxx/test/std/containers/views/mdspan/CustomTestLayouts.h @@ -14,8 +14,8 @@ // //===---------------------------------------------------------------------===// -#ifndef TEST_STD_CONTAINERS_VIEWS_MDSPAN_MDSPAN_CUSTOM_TEST_LAYOUTS_H -#define TEST_STD_CONTAINERS_VIEWS_MDSPAN_MDSPAN_CUSTOM_TEST_LAYOUTS_H +#ifndef TEST_STD_CONTAINERS_VIEWS_MDSPAN_CUSTOM_TEST_LAYOUTS_H +#define TEST_STD_CONTAINERS_VIEWS_MDSPAN_CUSTOM_TEST_LAYOUTS_H #include #include @@ -208,6 +208,7 @@ // This layout does not check convertibility of extents for its conversion ctor // Allows triggering mdspan's ctor static assertion on convertibility of extents +// It also allows for negative strides and offsets via runtime arguments class always_convertible_layout { public: template @@ -239,8 +240,9 @@ public: constexpr mapping() noexcept = delete; - constexpr mapping(const mapping& other) noexcept : extents_(other.extents()){}; - constexpr mapping(const extents_type& ext) noexcept : extents_(ext){}; + constexpr mapping(const mapping& other) noexcept : extents_(other.extents_), offset_(other.offset_), scaling_(other.scaling_){}; + constexpr mapping(const extents_type& ext, index_type offset = 0, index_type scaling = 1) noexcept + : extents_(ext), offset_(offset), scaling_(scaling){}; template constexpr mapping(const mapping& other) noexcept { @@ -256,10 +258,14 @@ } else { extents_ = extents_type(); } + offset_ = other.offset_; + scaling_ = other.scaling_; } constexpr mapping& operator=(const mapping& other) noexcept { extents_ = other.extents_; + offset_ = other.offset_; + scaling_ = other.scaling_; return *this; }; @@ -269,7 +275,7 @@ index_type size = 1; for (size_t r = 0; r < extents_type::rank(); r++) size *= extents_.extent(r); - return size; + return std::max(size*scaling_ + offset_, offset_); } template @@ -277,16 +283,16 @@ (std::is_nothrow_constructible_v && ...)) constexpr index_type operator()(Indices... idx) const noexcept { std::array idx_a{static_cast(static_cast(idx))...}; - return [&](std::index_sequence) { + return offset_ + scaling_ * ([&](std::index_sequence) { index_type res = 0; ((res = idx_a[extents_type::rank() - 1 - Pos] + extents_.extent(extents_type::rank() - 1 - Pos) * res), ...); return res; - }(std::make_index_sequence()); + }(std::make_index_sequence())); } - static constexpr bool is_always_unique() noexcept { return false; } + static constexpr bool is_always_unique() noexcept { return true; } static constexpr bool is_always_exhaustive() noexcept { return true; } - static constexpr bool is_always_strided() noexcept { return false; } + static constexpr bool is_always_strided() noexcept { return true; } static constexpr bool is_unique() noexcept { return true; } static constexpr bool is_exhaustive() noexcept { return true; } @@ -296,15 +302,15 @@ requires(extents_type::rank() > 0) { index_type s = 1; - for (rank_type i = extents_type::rank() - 1; i > r; i--) + for (rank_type i = 0; i < r; i++) s *= extents_.extent(i); - return s; + return s*scaling_; } template requires(OtherExtents::rank() == extents_type::rank()) friend constexpr bool operator==(const mapping& lhs, const mapping& rhs) noexcept { - return lhs.extents() == rhs.extents(); + return lhs.extents() == rhs.extents() && lhs.offset_ == rhs.offset && lhs.scaling_ == rhs.scaling_; } friend constexpr void swap(mapping& x, mapping& y) noexcept { @@ -320,6 +326,11 @@ } private: + template + friend class mapping; + extents_type extents_{}; + index_type offset_{}; + index_type scaling_{}; }; -#endif // TEST_STD_CONTAINERS_VIEWS_MDSPAN_MDSPAN_CUSTOM_TEST_LAYOUTS_H +#endif // TEST_STD_CONTAINERS_VIEWS_MDSPAN_CUSTOM_TEST_LAYOUTS_H Index: libcxx/test/std/containers/views/mdspan/layout_stride/comparison.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/containers/views/mdspan/layout_stride/comparison.pass.cpp @@ -0,0 +1,182 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template +// friend constexpr bool operator==(const mapping& x, const OtherMapping& y) noexcept; +// +// Constraints: +// - layout-mapping-alike is satisfied. +// - rank_ == OtherMapping::extents_type::rank() is true. +// - OtherMapping::is_always_strided() is true. +// +// Preconditions: OtherMapping meets the layout mapping requirements ([mdspan.layout.policy.reqmts]). +// +// Returns: true if x.extents() == y.extents() is true, OFFSET(y) == 0 is true, and each of x.stride(r) == y.stride(r) is true for r in the range [0, x.extents().rank()). Otherwise, false. + +#include +#include +#include +#include + +#include "test_macros.h" + +#include "../CustomTestLayouts.h" + +template +constexpr void test_comparison(bool equal, To dest_exts, From src_exts, + std::array dest_strides, + std::array src_strides) { + std::layout_stride::mapping dest(dest_exts, dest_strides); + std::layout_stride::mapping src(src_exts, src_strides); + ASSERT_NOEXCEPT(dest == src); + assert((dest == src) == equal); + assert((dest != src) == !equal); +} + +struct X { + constexpr bool does_not_match() { return true; } +}; + +constexpr X compare_layout_mappings(...) { return {}; } + +template +constexpr auto compare_layout_mappings(E1 e1, std::array s1, E2 e2, std::array s2) + -> decltype(std::layout_stride::mapping(e1, s1) == std::layout_stride::mapping(e2, s2)) { + return true; +} + +template +constexpr void test_comparison_different_rank() { + constexpr size_t D = std::dynamic_extent; + + using arr_0 = std::array; + using arr_1 = std::array; + using arr_2 = std::array; + + // sanity check same rank + static_assert(compare_layout_mappings(std::extents(5), arr_1{1}, std::extents(5), arr_1{1})); + static_assert(compare_layout_mappings(std::extents(), arr_1{1}, std::extents(5), arr_1{1})); + static_assert(compare_layout_mappings(std::extents(5), arr_1{1}, std::extents(), arr_1{1})); + static_assert(compare_layout_mappings(std::extents(), arr_1{1}, std::extents(), arr_1{1})); + + // not equality comparable when rank is not the same + static_assert(compare_layout_mappings(std::extents(), arr_0{}, std::extents(1), arr_1{1}).does_not_match()); + static_assert(compare_layout_mappings(std::extents(), arr_0{}, std::extents(), arr_1{1}).does_not_match()); + + static_assert(compare_layout_mappings(std::extents(1), arr_1{1}, std::extents(), arr_0{}).does_not_match()); + static_assert(compare_layout_mappings(std::extents(), arr_1{1}, std::extents(), arr_0{}).does_not_match()); + + static_assert(compare_layout_mappings(std::extents(5), arr_1{1}, std::extents(5, 5), arr_2{1, 5}).does_not_match()); + static_assert(compare_layout_mappings(std::extents(), arr_1{1}, std::extents(5), arr_2{1, 5}).does_not_match()); + static_assert(compare_layout_mappings(std::extents(), arr_1{1}, std::extents(), arr_2{1, 5}).does_not_match()); + + static_assert(compare_layout_mappings(std::extents(5, 5), arr_2{1, 5}, std::extents(5), arr_1{1}).does_not_match()); + static_assert(compare_layout_mappings(std::extents(5), arr_2{1, 5}, std::extents(5), arr_1{1}).does_not_match()); + static_assert(compare_layout_mappings(std::extents(), arr_2{1, 5}, std::extents(), arr_1{1}).does_not_match()); +} + +template +constexpr void test_comparison_same_rank() { + constexpr size_t D = std::dynamic_extent; + + test_comparison(true, std::extents(), std::extents(), + std::array{}, std::array{}); + + test_comparison(true, std::extents(5), std::extents(5), + std::array{1}, std::array{1}); + test_comparison(true, std::extents(), std::extents(5), + std::array{3}, std::array{3}); + test_comparison(true, std::extents(5), std::extents(), + std::array{1}, std::array{1}); + test_comparison(true, std::extents(), std::extents< T2, 5>(), + std::array{1}, std::array{1}); + test_comparison(false, std::extents(), std::extents(5), + std::array{2}, std::array{1}); + test_comparison(false, std::extents(5), std::extents(5), + std::array{2}, std::array{1}); + test_comparison(false, std::extents(5), std::extents(7), + std::array{1}, std::array{1}); + test_comparison(false, std::extents(), std::extents(7), + std::array{1}, std::array{1}); + test_comparison(false, std::extents(5), std::extents(), + std::array{1}, std::array{1}); + test_comparison(false, std::extents(), std::extents(), + std::array{1}, std::array{1}); + + test_comparison(true, std::extents(5, 6, 7, 8, 9), std::extents(5, 6, 7, 8, 9), + std::array{2, 20, 200, 2000, 20000}, std::array{2, 20, 200, 2000, 20000}); + test_comparison(true, std::extents(5, 7, 9), std::extents(6, 7), + std::array{2, 20, 200, 2000, 20000}, std::array{2, 20, 200, 2000, 20000}); + test_comparison(true, std::extents(5, 6, 7, 8, 9), std::extents(), + std::array{2, 20, 200, 2000, 20000}, std::array{2, 20, 200, 2000, 20000}); + test_comparison(false, std::extents(5, 6, 7, 8, 9), std::extents(), + std::array{2, 20, 200, 20000, 2000}, std::array{2, 20, 200, 2000, 20000}); + test_comparison( + false, std::extents(5, 6, 7, 8, 9), std::extents(5, 6, 3, 8, 9), + std::array{2, 20, 200, 2000, 20000}, std::array{2, 20, 200, 2000, 20000}); + test_comparison(false, std::extents(5, 7, 9), std::extents(6, 7), + std::array{2, 20, 200, 2000, 20000}, std::array{2, 20, 200, 2000, 20000}); + test_comparison(false, std::extents(5, 6, 7, 8, 9), std::extents(), + std::array{2, 20, 200, 2000, 20000}, std::array{2, 20, 200, 2000, 20000}); +} + +template +constexpr void test_comparison_with(bool expect_equal, E1 e1, std::array strides, E2 e2, OtherArgs ... other_args){ + typename std::layout_stride::template mapping map(e1, strides); + typename OtherLayout::template mapping other_map(e2, other_args...); + + assert((map == other_map) == expect_equal); +} + +template +constexpr void test_comparison_with() { + constexpr size_t D = std::dynamic_extent; + bool is_left_based = std::is_same_v || + std::is_same_v; + test_comparison_with(true, std::extents(), std::array{}, std::extents()); + test_comparison_with(true, std::extents(), std::array{1}, std::extents()); + test_comparison_with(true, std::extents(5), std::array{1}, std::extents()); + test_comparison_with(false, std::extents(5), std::array{2}, std::extents()); + test_comparison_with(is_left_based, std::extents(5, 7), std::array{1, 5}, std::extents(5, 7)); + test_comparison_with(!is_left_based, std::extents(5, 7), std::array{7, 1}, std::extents(5, 7)); + test_comparison_with(false, std::extents(5, 7), std::array{8, 1}, std::extents(5, 7)); + + if constexpr (std::is_same_v) { + // test layout with strides not equal to product of extents + test_comparison_with(true, std::extents(5, 7), std::array{2, 10}, std::extents(5, 7), 0, 2); + // make sure that offset != 0 results in false + test_comparison_with(false, std::extents(5, 7), std::array{2, 10}, std::extents(5, 7), 1, 2); + } +} + +template +constexpr void test_comparison_index_type() { + test_comparison_same_rank(); + test_comparison_different_rank(); + test_comparison_with(); + test_comparison_with(); + test_comparison_with(); +} + +constexpr bool test() { + test_comparison_index_type(); + test_comparison_index_type(); + test_comparison_index_type(); + test_comparison_index_type(); + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + return 0; +} Index: libcxx/test/std/containers/views/mdspan/layout_stride/ctor.default.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/containers/views/mdspan/layout_stride/ctor.default.pass.cpp @@ -0,0 +1,73 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// Test default construction: +// +// constexpr mapping() noexcept; +// +// +// Preconditions: layout_right::mapping().required_span_size() is representable as a value of type index_type ([basic.fundamental]). +// +// Effects: Direct-non-list-initializes extents_ with extents_type(), and for all d in the range [0, rank_), +// direct-non-list-initializes strides_[d] with layout_right::mapping().stride(d). + +#include +#include +#include + +#include "test_macros.h" + +template +constexpr void test_construction() { + using M = std::layout_stride::mapping; + ASSERT_NOEXCEPT(M{}); + M m; + E e; + + // check correct extents are returned + ASSERT_NOEXCEPT(m.extents()); + assert(m.extents() == e); + + // check required_span_size() + typename E::index_type expected_size = 1; + for (typename E::rank_type r = 0; r < E::rank(); r++) + expected_size *= e.extent(r); + assert(m.required_span_size() == expected_size); + + // check strides: node stride function is constrained on rank>0, e.extent(r) is not + auto strides = m.strides(); + ASSERT_NOEXCEPT(m.strides()); + if constexpr (E::rank() > 0) { + std::layout_right::mapping m_right; + for (typename E::rank_type r = 0; r < E::rank(); r++) { + assert(m.stride(r) == m_right.stride(r)); + assert(strides[r] == m.stride(r)); + } + } +} + +constexpr bool test() { + constexpr size_t D = std::dynamic_extent; + test_construction>(); + test_construction>(); + test_construction>(); + test_construction>(); + test_construction>(); + test_construction>(); + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + return 0; +} Index: libcxx/test/std/containers/views/mdspan/layout_stride/ctor.extents_array.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/containers/views/mdspan/layout_stride/ctor.extents_array.pass.cpp @@ -0,0 +1,135 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template +// constexpr mapping(const extents_type& e, array s) noexcept; +// +// Constraints: +// - is_convertible_v is true, and +// - is_nothrow_constructible_v is true. +// +// Preconditions: +// - s[i] > 0 is true for all i in the range [0, rank_). +// - REQUIRED-SPAN-SIZE(e, s) is representable as a value of type index_type ([basic.fundamental]). +// - If rank_ is greater than 0, then there exists a permutation P of the integers in the range [0, rank_), +// such that s[pi] >= s[pi_1] * e.extent(pi_1) is true for all i in the range [1, rank_), where pi is the ith element of P. +// Note 1: For layout_stride, this condition is necessary and sufficient for is_unique() to be true. +// +// Effects: Direct-non-list-initializes extents_ with e, and for all d in the range [0, rank_), +// direct-non-list-initializes strides_[d] with as_const(s[d]). + +#include +#include +#include + +#include "test_macros.h" +#include "../ConvertibleToIntegral.h" + +template +constexpr void test_construction(E e, S s) { + using M = std::layout_stride::mapping; + ASSERT_NOEXCEPT(M{e, s}); + M m(e, s); + + // check correct extents are returned + ASSERT_NOEXCEPT(m.extents()); + assert(m.extents() == e); + + // check required_span_size() + typename E::index_type expected_size = 1; + for (typename E::rank_type r = 0; r < E::rank(); r++) { + if (e.extent(r) == 0) { expected_size = 0; break; } + expected_size += (e.extent(r) - 1) * static_cast(s[r]); + } + assert(m.required_span_size() == expected_size); + + // check strides: node stride function is constrained on rank>0, e.extent(r) is not + auto strides = m.strides(); + ASSERT_NOEXCEPT(m.strides()); + if constexpr (E::rank() > 0) { + for (typename E::rank_type r = 0; r < E::rank(); r++) { + assert(m.stride(r) == static_cast(s[r])); + assert(strides[r] == m.stride(r)); + } + } +} + +constexpr bool test() { + constexpr size_t D = std::dynamic_extent; + { + std::array s{}; + test_construction(std::extents(), s); + } + { + std::array s{1}; + test_construction(std::extents(7), s); + } + { + std::array s{1}; + test_construction(std::extents(0), s); + } + { + std::array s{2}; + test_construction(std::extents(), s); + } + { + std::array s{1}; + test_construction(std::extents(7), s); + } + { + std::array s{3, 30}; + test_construction(std::extents(), s); + } + { + std::array s{20, 2, 200, 2000}; + test_construction(std::extents(7, 9, 10), s); + test_construction(std::extents(0, 9, 10), s); + test_construction(std::extents(0, 8, 0), s); + } + { + std::array s{200, 20, 20, 2000}; + test_construction(std::extents(7, 0, 8, 9), s); + test_construction(std::extents(7, 8, 0, 9), s); + test_construction(std::extents(7, 1, 8, 9), s); + test_construction(std::extents(7, 8, 1, 9), s); + test_construction(std::extents(7, 1, 1, 9), s); + test_construction(std::extents(7, 0, 0, 9), s); + test_construction(std::extents(7, 1, 1, 9), s); + test_construction(std::extents(7, 1, 0, 9), s); + test_construction(std::extents(7, 0, 1, 9), s); + } + + { + using mapping_t = std::layout_stride::mapping>; + // wrong strides size + static_assert(!std::is_constructible_v, std::array>); + static_assert(!std::is_constructible_v, std::array>); + // wrong extents rank + static_assert(!std::is_constructible_v, std::array>); + // none-convertible strides + static_assert(!std::is_constructible_v, std::array>); + } + { + // not no-throw constructible index_type from stride + using mapping_t = std::layout_stride::mapping>; + static_assert(std::is_convertible_v); + static_assert(!std::is_constructible_v, std::array>); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + return 0; +} Index: libcxx/test/std/containers/views/mdspan/layout_stride/ctor.extents_span.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/containers/views/mdspan/layout_stride/ctor.extents_span.pass.cpp @@ -0,0 +1,138 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template +// constexpr mapping(const extents_type& e, span s) noexcept; +// +// Constraints: +// - is_convertible_v is true, and +// - is_nothrow_constructible_v is true. +// +// Preconditions: +// - s[i] > 0 is true for all i in the range [0, rank_). +// - REQUIRED-SPAN-SIZE(e, s) is representable as a value of type index_type ([basic.fundamental]). +// - If rank_ is greater than 0, then there exists a permutation P of the integers in the range [0, rank_), +// such that s[pi] >= s[pi_1] * e.extent(pi_1) is true for all i in the range [1, rank_), where pi is the ith element of P. +// Note 1: For layout_stride, this condition is necessary and sufficient for is_unique() to be true. +// +// Effects: Direct-non-list-initializes extents_ with e, and for all d in the range [0, rank_), +// direct-non-list-initializes strides_[d] with as_const(s[d]). + +#include +#include +#include + +#include "test_macros.h" +#include "../ConvertibleToIntegral.h" + +template +constexpr void test_construction(E e, S s) { + using M = std::layout_stride::mapping; + ASSERT_NOEXCEPT(M{e, s}); + M m(e, s); + + // check correct extents are returned + ASSERT_NOEXCEPT(m.extents()); + assert(m.extents() == e); + + // check required_span_size() + typename E::index_type expected_size = 1; + for (typename E::rank_type r = 0; r < E::rank(); r++) { + if (e.extent(r) == 0) { expected_size = 0; break; } + expected_size += (e.extent(r) - 1) * static_cast(s[r]); + } + assert(m.required_span_size() == expected_size); + + // check strides: node stride function is constrained on rank>0, e.extent(r) is not + auto strides = m.strides(); + ASSERT_NOEXCEPT(m.strides()); + if constexpr (E::rank() > 0) { + for (typename E::rank_type r = 0; r < E::rank(); r++) { + assert(m.stride(r) == static_cast(s[r])); + assert(strides[r] == m.stride(r)); + } + } +} + +constexpr bool test() { + constexpr size_t D = std::dynamic_extent; + { + std::array s{}; + test_construction(std::extents(), std::span(s)); + } + { + std::array s{1}; + test_construction(std::extents(7), std::span(s)); + } + { + std::array s{1}; + test_construction(std::extents(0), std::span(s)); + } + { + std::array s{2}; + test_construction(std::extents(), std::span(s)); + } + { + std::array s{1}; + test_construction(std::extents(7), std::span(s)); + } + { + std::array s{3, 30}; + test_construction(std::extents(), std::span(s)); + } + { + std::array s{20, 2, 200, 2000}; + test_construction(std::extents(7, 9, 10), std::span(s)); + } + { + std::array s{20, 2, 200, 2000}; + test_construction(std::extents(7, 0, 10), std::span(s)); + test_construction(std::extents(0, 9, 10), std::span(s)); + test_construction(std::extents(0, 8, 0), std::span(s)); + } + { + std::array s{200, 20, 20, 2000}; + test_construction(std::extents(7, 0, 8, 9), std::span(s)); + test_construction(std::extents(7, 8, 0, 9), std::span(s)); + test_construction(std::extents(7, 1, 8, 9), std::span(s)); + test_construction(std::extents(7, 8, 1, 9), std::span(s)); + test_construction(std::extents(7, 1, 1, 9), std::span(s)); + test_construction(std::extents(7, 0, 0, 9), std::span(s)); + test_construction(std::extents(7, 1, 1, 9), std::span(s)); + test_construction(std::extents(7, 1, 0, 9), std::span(s)); + test_construction(std::extents(7, 0, 1, 9), std::span(s)); + } + + { + using mapping_t = std::layout_stride::mapping>; + // wrong strides size + static_assert(!std::is_constructible_v, std::span>); + static_assert(!std::is_constructible_v, std::span>); + // wrong extents rank + static_assert(!std::is_constructible_v, std::span>); + // none-convertible strides + static_assert(!std::is_constructible_v, std::span>); + } + { + // not no-throw constructible index_type from stride + using mapping_t = std::layout_stride::mapping>; + static_assert(std::is_convertible_v); + static_assert(!std::is_constructible_v, std::span>); + } + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + return 0; +} Index: libcxx/test/std/containers/views/mdspan/layout_stride/ctor.strided_mapping.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/containers/views/mdspan/layout_stride/ctor.strided_mapping.pass.cpp @@ -0,0 +1,191 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template +// constexpr explicit(see below) +// mapping(const StridedLayoutMapping& other) noexcept; +// +// Constraints: +// - layout-mapping-alike is satisfied. +// - is_constructible_v is true. +// - StridedLayoutMapping::is_always_unique() is true. +// - StridedLayoutMapping::is_always_strided() is true. +// +// Preconditions: +// - StridedLayoutMapping meets the layout mapping requirements ([mdspan.layout.policy.reqmts]), +// - other.stride(r) > 0 is true for every rank index r of extents(), +// - other.required_span_size() is representable as a value of type index_type ([basic.fundamental]), and +// - OFFSET(other) == 0 is true. +// +// Effects: Direct-non-list-initializes extents_ with other.extents(), and for all d in the range [0, rank_), +// direct-non-list-initializes strides_[d] with other.stride(d). +// +// Remarks: The expression inside explicit is equivalent to: +// - !(is_convertible_v && +// (is-mapping-of || +// is-mapping-of || +// is-mapping-of)) + +#include +#include +#include +#include + +#include "test_macros.h" + +#include "../CustomTestLayouts.h" + +template +constexpr void test_implicit_conversion(To dest, From src) { + assert(dest == src); +} + +template +constexpr void test_conversion(FromE src_exts) { + using To = std::layout_stride::mapping; + using From = FromL::template mapping; + + From src([&]() { + if constexpr (std::is_same_v) { + // just construct some strides which aren't layout_left/layout_right + std::array strides; + size_t stride = 2; + for(size_t r=0; r(src, src); + } else { + assert((!std::is_convertible_v)); + } +} + +template +constexpr void test_conversion() { + constexpr size_t D = std::dynamic_extent; + constexpr bool idx_convertible = + static_cast(std::numeric_limits::max()) >= static_cast(std::numeric_limits::max()); + constexpr bool l_convertible = + std::is_same_v || std::is_same_v || std::is_same_v; + constexpr bool idx_l_convertible = idx_convertible && l_convertible; + + // clang-format off + // adding extents convertibility expectation + test_conversion>(std::extents()); + test_conversion>(std::extents(5)); + test_conversion>(std::extents(5)); + test_conversion>(std::extents()); + test_conversion>(std::extents(5, 5)); + test_conversion>(std::extents(5, 5)); + test_conversion>(std::extents(5)); + test_conversion>(std::extents()); + test_conversion>(std::extents(5, 7)); + test_conversion>( + std::extents(5, 7, 8, 9, 1)); + test_conversion>(std::extents(5)); + test_conversion>(std::extents()); + // clang-format on +} + +template +using ToM = typename std::layout_stride::template mapping>; + +template +using FromM = typename FromL::template mapping>; + +template +constexpr void test_no_implicit_conversion() { + constexpr size_t D = std::dynamic_extent; + + // Sanity check that one static to dynamic conversion works + static_assert(std::is_constructible_v, FromM>); + static_assert(std::is_convertible_v, ToM>); + + // Check that dynamic to static conversion only works explicitly + static_assert(std::is_constructible_v, FromM>); + static_assert(!std::is_convertible_v, ToM>); + + // Sanity check that one static to dynamic conversion works + static_assert(std::is_constructible_v, FromM>); + static_assert(std::is_convertible_v, ToM>); + + // Check that dynamic to static conversion only works explicitly + static_assert(std::is_constructible_v, FromM>); + static_assert(!std::is_convertible_v, ToM>); + + // Sanity check that smaller index_type to larger index_type conversion works + static_assert(std::is_constructible_v, FromM>); + static_assert(std::is_convertible_v, ToM>); + + // Check that larger index_type to smaller index_type conversion works explicitly only + static_assert(std::is_constructible_v, FromM>); + static_assert(!std::is_convertible_v, ToM>); +} + +template +constexpr void test_rank_mismatch() { + constexpr size_t D = std::dynamic_extent; + + static_assert(!std::is_constructible_v, FromM>); + static_assert(!std::is_constructible_v, FromM>); + static_assert(!std::is_constructible_v, FromM>); + static_assert(!std::is_constructible_v, FromM>); +} + +template +constexpr void test_static_extent_mismatch() { + constexpr size_t D = std::dynamic_extent; + + static_assert(!std::is_constructible_v, FromM>); + static_assert(!std::is_constructible_v, FromM>); + static_assert(!std::is_constructible_v, FromM>); +} + +template +constexpr void test_layout() { + test_conversion(); + test_conversion(); + test_conversion(); + test_conversion(); + // the implicit convertibility test doesn't apply to non std::layouts + if constexpr (!std::is_same_v) + test_no_implicit_conversion(); + test_rank_mismatch(); + test_static_extent_mismatch(); +} + +constexpr bool test() { + test_layout(); + test_layout(); + test_layout(); + test_layout(); + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + return 0; +} Index: libcxx/test/std/containers/views/mdspan/layout_stride/extents.verify.cpp =================================================================== --- /dev/null +++ libcxx/test/std/containers/views/mdspan/layout_stride/extents.verify.cpp @@ -0,0 +1,33 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template +// class layout_stride::mapping; + +// If Extents is not a specialization of extents, then the program is +// ill-formed. + +// Mandates: If Extents::rank_dynamic() == 0 is true, then the size of the +// multidimensional index space Extents() is representable as a value of type +// typename Extents::index_type. + +#include + +void not_extents() { + // expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}layout_stride::mapping template argument must be a specialization of extents}} + [[maybe_unused]] std::layout_stride::mapping mapping; +} + +void representable() { + // expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}layout_stride::mapping product of static extents must be representable as index_type.}} + [[maybe_unused]] std::layout_stride::mapping> mapping; +} Index: libcxx/test/std/containers/views/mdspan/layout_stride/index_operator.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/containers/views/mdspan/layout_stride/index_operator.pass.cpp @@ -0,0 +1,121 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// Test default iteration: +// +// template +// constexpr index_type operator()(Indices...) const noexcept; +// +// Constraints: +// * sizeof...(Indices) == extents_type::rank() is true, +// * (is_convertible_v && ...) is true, and +// * (is_nothrow_constructible_v && ...) is true. +// +// Preconditions: +// * extents_type::index-cast(i) is a multidimensional index in extents_. + +#include +#include +#include + +#include "test_macros.h" + +#include "../ConvertibleToIntegral.h" + +template +concept operator_constraints = requires(Mapping m, Indices... idxs) { + { std::is_same_v }; +}; + +template + requires(operator_constraints) +constexpr bool check_operator_constraints(Mapping m, Indices... idxs) { + (void)m(idxs...); + return true; +} + +template +constexpr bool check_operator_constraints(Mapping, Indices...) { + return false; +} + +template +constexpr void iterate_stride(M m, const std::array& strides, Args... args) { + constexpr int r = static_cast(M::extents_type::rank()) - 1 - static_cast(sizeof...(Args)); + if constexpr (-1 == r) { + ASSERT_NOEXCEPT(m(args...)); + size_t expected_val = [&](std::index_sequence) { + return ((args * strides[Pos]) + ... + 0); + }(std::make_index_sequence()); + assert(expected_val == static_cast(m(args...))); + } else { + for (typename M::index_type i = 0; i < m.extents().extent(r); i++) { + iterate_stride(m, strides, i, args...); + } + } +} + +template +constexpr void test_iteration(std::array strides, Args... args) { + using M = std::layout_stride::mapping; + M m(E(args...), strides); + + iterate_stride(m, strides); +} + +constexpr bool test() { + constexpr size_t D = std::dynamic_extent; + test_iteration>(std::array{}); + test_iteration>(std::array{2}, 1); + test_iteration>(std::array{3}, 7); + test_iteration>(std::array{4}); + test_iteration>(std::array{25, 3}); + test_iteration>(std::array{1, 1, 1, 1}, 1, 1, 1, 1); + + // Check operator constraint for number of arguments + static_assert(check_operator_constraints( + std::layout_stride::mapping>(std::extents(1), std::array{1}), 0)); + static_assert(!check_operator_constraints( + std::layout_stride::mapping>(std::extents(1), std::array{1}), 0, 0)); + + // Check operator constraint for convertibility of arguments to index_type + static_assert(check_operator_constraints( + std::layout_stride::mapping>(std::extents(1), std::array{1}), IntType(0))); + static_assert(!check_operator_constraints( + std::layout_stride::mapping>(std::extents(1), std::array{1}), IntType(0))); + + // Check operator constraint for no-throw-constructibility of index_type from arguments + static_assert(!check_operator_constraints( + std::layout_stride::mapping>(std::extents(1), std::array{1}), + IntType(0))); + + return true; +} + +constexpr bool test_large() { + constexpr size_t D = std::dynamic_extent; + test_iteration>(std::array{2000, 2, 20, 200}, 7, 9, 10); + test_iteration>(std::array{2000, 20, 20, 200}, 7, 10); + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + // The large test iterates over ~10k loop indices. + // With assertions enabled this triggered the maximum default limit + // for steps in consteval expressions. Assertions roughly double the + // total number of instructions, so this was already close to the maximum. + test_large(); + return 0; +} Index: libcxx/test/std/containers/views/mdspan/layout_stride/is_exhaustive_corner_case.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/containers/views/mdspan/layout_stride/is_exhaustive_corner_case.pass.cpp @@ -0,0 +1,52 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// constexpr bool is_exhaustive() const noexcept; +// +// Returns: +// - true if rank_ is 0. +// - Otherwise, true if there is a permutation P of the integers in the range [0, rank_) such that +// stride(p0) equals 1, and stride(pi) equals stride(pi_1) * extents().extent(pi_1) for i in the +// range [1, rank_), where pi is the ith element of P. +// - Otherwise, false. + +#include +#include +#include +#include + +#include "test_macros.h" + +template +constexpr void test_layout_mapping_stride(E ext, std::array strides, bool exhaustive) { + using M = std::layout_stride::template mapping; + M m(ext, strides); + assert(m.is_exhaustive() == exhaustive); +} + +constexpr bool test() { + constexpr size_t D = std::dynamic_extent; + test_layout_mapping_stride(std::extents(), std::array{1}, true); + test_layout_mapping_stride(std::extents(0), std::array{3}, true); + test_layout_mapping_stride(std::extents(), std::array{6,2}, true); + test_layout_mapping_stride(std::extents(3, 0), std::array{6,2}, false); + test_layout_mapping_stride(std::extents(0, 0), std::array{6,2}, false); + test_layout_mapping_stride(std::extents(3,3,0,3),std::array{3,1,27,9}, true); + test_layout_mapping_stride(std::extents(0,3,3,3),std::array{3,1,27,9}, false); + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + return 0; +} Index: libcxx/test/std/containers/views/mdspan/layout_stride/properties.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/containers/views/mdspan/layout_stride/properties.pass.cpp @@ -0,0 +1,83 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// namespace std { +// template +// class layout_stride::mapping { +// +// ... +// static constexpr bool is_always_unique() noexcept { return true; } +// static constexpr bool is_always_exhaustive() noexcept { return false; } +// static constexpr bool is_always_strided() noexcept { return true; } +// +// static constexpr bool is_unique() noexcept { return true; } +// static constexpr bool is_exhaustive() noexcept; +// static constexpr bool is_strided() noexcept { return true; } +// ... +// }; +// } +// +// +// layout_stride::mapping is a trivially copyable type that models regular for each E. +// +// constexpr bool is_exhaustive() const noexcept; +// +// Returns: +// - true if rank_ is 0. +// - Otherwise, true if there is a permutation P of the integers in the range [0, rank_) such that +// stride(p0) equals 1, and stride(pi) equals stride(pi_1) * extents().extent(pi_1) for i in the +// range [1, rank_), where pi is the ith element of P. +// - Otherwise, false. + + +#include +#include +#include +#include + +#include "test_macros.h" + +template +constexpr void test_layout_mapping_stride(E ext, std::array strides, bool exhaustive) { + using M = std::layout_stride::template mapping; + M m(ext, strides); + assert(M::is_unique() == true); + assert(m.is_exhaustive() == exhaustive); + assert(M::is_strided() == true); + assert(M::is_always_unique() == true); + assert(M::is_always_exhaustive() == false); + assert(M::is_always_strided() == true); + ASSERT_NOEXCEPT(std::declval().is_unique()); + ASSERT_NOEXCEPT(std::declval().is_exhaustive()); + ASSERT_NOEXCEPT(std::declval().is_strided()); + ASSERT_NOEXCEPT(M::is_always_unique()); + ASSERT_NOEXCEPT(M::is_always_exhaustive()); + ASSERT_NOEXCEPT(M::is_always_strided()); + static_assert(std::is_trivially_copyable_v); + static_assert(std::regular); +} + +constexpr bool test() { + constexpr size_t D = std::dynamic_extent; + test_layout_mapping_stride(std::extents(), std::array{}, true); + test_layout_mapping_stride(std::extents(), std::array{1,4}, true); + test_layout_mapping_stride(std::extents(), std::array{1,5}, false); + test_layout_mapping_stride(std::extents(7), std::array{20,2}, false); + test_layout_mapping_stride(std::extents(3,3,3,3),std::array{3,1,9,27}, true); + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + return 0; +} Index: libcxx/test/std/containers/views/mdspan/layout_stride/required_span_size.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/containers/views/mdspan/layout_stride/required_span_size.pass.cpp @@ -0,0 +1,56 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// Let REQUIRED-SPAN-SIZE(e, strides) be: +// - 1, if e.rank() == 0 is true, +// - otherwise 0, if the size of the multidimensional index space e is 0, +// - otherwise 1 plus the sum of products of (e.extent(r) - 1) and strides[r] for all r in the range [0, e.rank()). + +// constexpr index_type required_span_size() const noexcept; +// +// Returns: REQUIRED-SPAN-SIZE(extents(), strides_). + + +#include +#include +#include + +#include "test_macros.h" + +template +constexpr void test_required_span_size(E e, std::array strides, typename E::index_type expected_size) { + using M = std::layout_stride::mapping; + const M m(e, strides); + + ASSERT_NOEXCEPT(m.required_span_size()); + assert(m.required_span_size() == expected_size); +} + +constexpr bool test() { + constexpr size_t D = std::dynamic_extent; + test_required_span_size(std::extents(), std::array{}, 1); + test_required_span_size(std::extents(0), std::array{5}, 0); + test_required_span_size(std::extents(1), std::array{5}, 1); + test_required_span_size(std::extents(7), std::array{5}, 31); + test_required_span_size(std::extents(), std::array{5}, 31); + test_required_span_size(std::extents(), std::array{20, 2}, 135); + test_required_span_size(std::extents(7, 9, 10), std::array{1, 7, 7*8, 7*8*9}, 5040); + test_required_span_size(std::extents(9, 10), std::array{1, 7, 7*8, 7*8*9}, 5034); + test_required_span_size(std::extents(9, 10), std::array{1, 7, 7*8, 7*8*9}, 0); + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + return 0; +} Index: libcxx/test/std/containers/views/mdspan/layout_stride/static_requirements.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/containers/views/mdspan/layout_stride/static_requirements.pass.cpp @@ -0,0 +1,132 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// A type M meets the layout mapping requirements if +// - M models copyable and equality_comparable, +// - is_nothrow_move_constructible_v is true, +// - is_nothrow_move_assignable_v is true, +// - is_nothrow_swappable_v is true, and +// +// the following types and expressions are well-formed and have the specified semantics. +// +// typename M::extents_type +// Result: A type that is a specialization of extents. +// +// typename M::index_type +// Result: typename M::extents_type::index_type. +// +// typename M::rank_type +// Result: typename M::extents_type::rank_type. +// +// typename M::layout_type +// Result: A type MP that meets the layout mapping policy requirements ([mdspan.layout.policy.reqmts]) and for which is-mapping-of is true. +// +// m.extents() +// Result: const typename M::extents_type& +// +// m(i...) +// Result: typename M::index_type +// Returns: A nonnegative integer less than numeric_limits::max() and less than or equal to numeric_limits::max(). +// +// m(i...) == m(static_cast(i)...) +// Result: bool +// Returns: true +// +// m.required_span_size() +// Result: typename M::index_type +// Returns: If the size of the multidimensional index space m.extents() is 0, then 0, else 1 plus the maximum value of m(i...) for all i. +// +// m.is_unique() +// Result: bool +// Returns: true only if for every i and j where (i != j || ...) is true, m(i...) != m(j...) is true. +// +// m.is_exhaustive() +// Result: bool +// Returns: true only if for all k in the range [0, m.required_span_size()) there exists an i such that m(i...) equals k. +// +// m.is_strided() +// Result: bool +// Returns: true only if for every rank index r of m.extents() there exists an integer +// sr such that, for all i where (i+dr) is a multidimensional index in m.extents() ([mdspan.overview]), +// m((i + dr)...) - m(i...) equals sr +// +// m.stride(r) +// Preconditions: m.is_strided() is true. +// Result: typename M::index_type +// Returns: sr as defined in m.is_strided() above. +// +// M::is_always_unique() +// Result: A constant expression ([expr.const]) of type bool. +// Returns: true only if m.is_unique() is true for all possible objects m of type M. +// +// M::is_always_exhaustive() +// Result: A constant expression ([expr.const]) of type bool. +// Returns: true only if m.is_exhaustive() is true for all possible objects m of type M. +// +// M::is_always_strided() +// Result: A constant expression ([expr.const]) of type bool. +// Returns: true only if m.is_strided() is true for all possible objects m of type M. + +#include +#include +#include +#include + +#include "test_macros.h" + +// Common requirements of all layout mappings +template +void test_mapping_requirements(std::index_sequence) { + using E = typename M::extents_type; + static_assert(std::__mdspan_detail::__is_extents_v); + static_assert(std::is_copy_constructible_v); + static_assert(std::is_nothrow_move_constructible_v); + static_assert(std::is_nothrow_move_assignable_v); + static_assert(std::is_nothrow_swappable_v); + ASSERT_SAME_TYPE(typename M::index_type, typename E::index_type); + ASSERT_SAME_TYPE(typename M::size_type, typename E::size_type); + ASSERT_SAME_TYPE(typename M::rank_type, typename E::rank_type); + ASSERT_SAME_TYPE(typename M::layout_type, std::layout_stride); + ASSERT_SAME_TYPE(typename M::layout_type::template mapping, M); + static_assert(std::is_same_v().extents()), const E&>); + static_assert(std::is_same_v().strides()), std::array>); + static_assert(std::is_same_v()(Idxs...)), typename M::index_type>); + static_assert(std::is_same_v().required_span_size()), typename M::index_type>); + static_assert(std::is_same_v().is_unique()), bool>); + static_assert(std::is_same_v().is_exhaustive()), bool>); + static_assert(std::is_same_v().is_strided()), bool>); + if constexpr (E::rank() > 0) + static_assert(std::is_same_v().stride(0)), typename M::index_type>); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); +} + +template +void test_layout_mapping_requirements() { + using M = typename L::template mapping; + test_mapping_requirements(std::make_index_sequence()); +} + +template +void test_layout_mapping_stride() { + test_layout_mapping_requirements(); +} + +int main(int, char**) { + constexpr size_t D = std::dynamic_extent; + test_layout_mapping_stride>(); + test_layout_mapping_stride>(); + test_layout_mapping_stride>(); + test_layout_mapping_stride>(); + return 0; +} Index: libcxx/test/std/containers/views/mdspan/layout_stride/stride.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/containers/views/mdspan/layout_stride/stride.pass.cpp @@ -0,0 +1,57 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// constexpr index_type stride(rank_type i) const noexcept; +// +// Constraints: extents_type::rank() > 0 is true. +// +// Preconditions: i < extents_type::rank() is true. +// +// Returns: extents().rev-prod-of-extents(i). + +#include +#include +#include +#include +#include +#include "test_macros.h" + +template +constexpr void test_stride(std::array strides, Args... args) { + using M = std::layout_stride::mapping; + M m(E(args...), strides); + + ASSERT_NOEXCEPT(m.stride(0)); + for (size_t r = 0; r < E::rank(); r++) + assert(strides[r] == m.stride(r)); + + ASSERT_NOEXCEPT(m.strides()); + auto strides_out = m.strides(); + static_assert(std::is_same_v>); + for (size_t r = 0; r < E::rank(); r++) + assert(strides[r] == strides_out[r]); +} + +constexpr bool test() { + constexpr size_t D = std::dynamic_extent; + test_stride>(std::array{1}, 7); + test_stride>(std::array{1}); + test_stride>(std::array{8, 1}); + test_stride>(std::array{720, 90, 10, 1}, 7, 9, 10); + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + return 0; +} Index: libcxx/test/std/containers/views/mdspan/mdspan/assign.pass.cpp =================================================================== --- libcxx/test/std/containers/views/mdspan/mdspan/assign.pass.cpp +++ libcxx/test/std/containers/views/mdspan/mdspan/assign.pass.cpp @@ -19,7 +19,7 @@ #include "test_macros.h" #include "../MinimalElementType.h" -#include "CustomTestLayouts.h" +#include "../CustomTestLayouts.h" #include "CustomTestAccessors.h" template Index: libcxx/test/std/containers/views/mdspan/mdspan/conversion.pass.cpp =================================================================== --- libcxx/test/std/containers/views/mdspan/mdspan/conversion.pass.cpp +++ libcxx/test/std/containers/views/mdspan/mdspan/conversion.pass.cpp @@ -43,7 +43,7 @@ #include "test_macros.h" #include "../MinimalElementType.h" -#include "CustomTestLayouts.h" +#include "../CustomTestLayouts.h" #include "CustomTestAccessors.h" template Index: libcxx/test/std/containers/views/mdspan/mdspan/conversion.verify.cpp =================================================================== --- libcxx/test/std/containers/views/mdspan/mdspan/conversion.verify.cpp +++ libcxx/test/std/containers/views/mdspan/mdspan/conversion.verify.cpp @@ -37,7 +37,7 @@ #include #include "CustomTestAccessors.h" -#include "CustomTestLayouts.h" +#include "../CustomTestLayouts.h" void cant_construct_data_handle_type() { int data; Index: libcxx/test/std/containers/views/mdspan/mdspan/ctor.copy.pass.cpp =================================================================== --- libcxx/test/std/containers/views/mdspan/mdspan/ctor.copy.pass.cpp +++ libcxx/test/std/containers/views/mdspan/mdspan/ctor.copy.pass.cpp @@ -21,7 +21,7 @@ #include "test_macros.h" #include "../MinimalElementType.h" -#include "CustomTestLayouts.h" +#include "../CustomTestLayouts.h" #include "CustomTestAccessors.h" template Index: libcxx/test/std/containers/views/mdspan/mdspan/ctor.default.pass.cpp =================================================================== --- libcxx/test/std/containers/views/mdspan/mdspan/ctor.default.pass.cpp +++ libcxx/test/std/containers/views/mdspan/mdspan/ctor.default.pass.cpp @@ -29,7 +29,7 @@ #include "test_macros.h" #include "../MinimalElementType.h" -#include "CustomTestLayouts.h" +#include "../CustomTestLayouts.h" #include "CustomTestAccessors.h" template Index: libcxx/test/std/containers/views/mdspan/mdspan/ctor.dh_array.pass.cpp =================================================================== --- libcxx/test/std/containers/views/mdspan/mdspan/ctor.dh_array.pass.cpp +++ libcxx/test/std/containers/views/mdspan/mdspan/ctor.dh_array.pass.cpp @@ -38,7 +38,7 @@ #include "../ConvertibleToIntegral.h" #include "../MinimalElementType.h" -#include "CustomTestLayouts.h" +#include "../CustomTestLayouts.h" #include "CustomTestAccessors.h" template Index: libcxx/test/std/containers/views/mdspan/mdspan/ctor.dh_extents.pass.cpp =================================================================== --- libcxx/test/std/containers/views/mdspan/mdspan/ctor.dh_extents.pass.cpp +++ libcxx/test/std/containers/views/mdspan/mdspan/ctor.dh_extents.pass.cpp @@ -31,7 +31,7 @@ #include "test_macros.h" #include "../MinimalElementType.h" -#include "CustomTestLayouts.h" +#include "../CustomTestLayouts.h" #include "CustomTestAccessors.h" template Index: libcxx/test/std/containers/views/mdspan/mdspan/ctor.dh_integers.pass.cpp =================================================================== --- libcxx/test/std/containers/views/mdspan/mdspan/ctor.dh_integers.pass.cpp +++ libcxx/test/std/containers/views/mdspan/mdspan/ctor.dh_integers.pass.cpp @@ -38,7 +38,7 @@ #include "test_macros.h" #include "../MinimalElementType.h" -#include "CustomTestLayouts.h" +#include "../CustomTestLayouts.h" #include "CustomTestAccessors.h" template Index: libcxx/test/std/containers/views/mdspan/mdspan/ctor.dh_map.pass.cpp =================================================================== --- libcxx/test/std/containers/views/mdspan/mdspan/ctor.dh_map.pass.cpp +++ libcxx/test/std/containers/views/mdspan/mdspan/ctor.dh_map.pass.cpp @@ -29,7 +29,7 @@ #include "test_macros.h" #include "../MinimalElementType.h" -#include "CustomTestLayouts.h" +#include "../CustomTestLayouts.h" #include "CustomTestAccessors.h" template Index: libcxx/test/std/containers/views/mdspan/mdspan/ctor.dh_map_acc.pass.cpp =================================================================== --- libcxx/test/std/containers/views/mdspan/mdspan/ctor.dh_map_acc.pass.cpp +++ libcxx/test/std/containers/views/mdspan/mdspan/ctor.dh_map_acc.pass.cpp @@ -26,7 +26,7 @@ #include "test_macros.h" #include "../MinimalElementType.h" -#include "CustomTestLayouts.h" +#include "../CustomTestLayouts.h" #include "CustomTestAccessors.h" template Index: libcxx/test/std/containers/views/mdspan/mdspan/ctor.dh_span.pass.cpp =================================================================== --- libcxx/test/std/containers/views/mdspan/mdspan/ctor.dh_span.pass.cpp +++ libcxx/test/std/containers/views/mdspan/mdspan/ctor.dh_span.pass.cpp @@ -38,7 +38,7 @@ #include "../ConvertibleToIntegral.h" #include "../MinimalElementType.h" -#include "CustomTestLayouts.h" +#include "../CustomTestLayouts.h" #include "CustomTestAccessors.h" template Index: libcxx/test/std/containers/views/mdspan/mdspan/ctor.move.pass.cpp =================================================================== --- libcxx/test/std/containers/views/mdspan/mdspan/ctor.move.pass.cpp +++ libcxx/test/std/containers/views/mdspan/mdspan/ctor.move.pass.cpp @@ -21,7 +21,7 @@ #include "test_macros.h" #include "../MinimalElementType.h" -#include "CustomTestLayouts.h" +#include "../CustomTestLayouts.h" #include "CustomTestAccessors.h" template Index: libcxx/test/std/containers/views/mdspan/mdspan/deduction.pass.cpp =================================================================== --- libcxx/test/std/containers/views/mdspan/mdspan/deduction.pass.cpp +++ libcxx/test/std/containers/views/mdspan/mdspan/deduction.pass.cpp @@ -55,7 +55,7 @@ #include "test_macros.h" #include "../MinimalElementType.h" -#include "CustomTestLayouts.h" +#include "../CustomTestLayouts.h" #include "CustomTestAccessors.h" template Index: libcxx/test/std/containers/views/mdspan/mdspan/index_operator.pass.cpp =================================================================== --- libcxx/test/std/containers/views/mdspan/mdspan/index_operator.pass.cpp +++ libcxx/test/std/containers/views/mdspan/mdspan/index_operator.pass.cpp @@ -36,7 +36,7 @@ #include "test_macros.h" #include "../ConvertibleToIntegral.h" -#include "CustomTestLayouts.h" +#include "../CustomTestLayouts.h" // Clang 15 and 16 do not support argument packs as input to operator [] #if defined(__clang_major__) && __clang_major__ < 17 Index: libcxx/test/std/containers/views/mdspan/mdspan/move.pass.cpp =================================================================== --- libcxx/test/std/containers/views/mdspan/mdspan/move.pass.cpp +++ libcxx/test/std/containers/views/mdspan/mdspan/move.pass.cpp @@ -21,7 +21,7 @@ #include "test_macros.h" #include "../MinimalElementType.h" -#include "CustomTestLayouts.h" +#include "../CustomTestLayouts.h" #include "CustomTestAccessors.h" template Index: libcxx/test/std/containers/views/mdspan/mdspan/properties.pass.cpp =================================================================== --- libcxx/test/std/containers/views/mdspan/mdspan/properties.pass.cpp +++ libcxx/test/std/containers/views/mdspan/mdspan/properties.pass.cpp @@ -58,7 +58,7 @@ #include "test_macros.h" #include "../MinimalElementType.h" -#include "CustomTestLayouts.h" +#include "../CustomTestLayouts.h" template constexpr void test_mdspan_types(const H& handle, const M& map, const A& acc) { Index: libcxx/test/std/containers/views/mdspan/mdspan/swap.pass.cpp =================================================================== --- libcxx/test/std/containers/views/mdspan/mdspan/swap.pass.cpp +++ libcxx/test/std/containers/views/mdspan/mdspan/swap.pass.cpp @@ -24,7 +24,7 @@ #include "test_macros.h" #include "../MinimalElementType.h" -#include "CustomTestLayouts.h" +#include "../CustomTestLayouts.h" template constexpr void test_swap(MDS a, MDS b) { Index: libcxx/test/std/containers/views/mdspan/mdspan/types.pass.cpp =================================================================== --- libcxx/test/std/containers/views/mdspan/mdspan/types.pass.cpp +++ libcxx/test/std/containers/views/mdspan/mdspan/types.pass.cpp @@ -36,7 +36,7 @@ #include "../MinimalElementType.h" #include "CustomTestAccessors.h" -#include "CustomTestLayouts.h" +#include "../CustomTestLayouts.h" // Calculated expected size of an mdspan // Note this expectes that only default_accessor is empty Index: libcxx/test/std/language.support/support.limits/support.limits.general/mdspan.version.compile.pass.cpp =================================================================== --- libcxx/test/std/language.support/support.limits/support.limits.general/mdspan.version.compile.pass.cpp +++ libcxx/test/std/language.support/support.limits/support.limits.general/mdspan.version.compile.pass.cpp @@ -65,17 +65,11 @@ #elif TEST_STD_VER == 23 -# if !defined(_LIBCPP_VERSION) -# ifndef __cpp_lib_mdspan -# error "__cpp_lib_mdspan should be defined in c++23" -# endif -# if __cpp_lib_mdspan != 202207L -# error "__cpp_lib_mdspan should have the value 202207L in c++23" -# endif -# else // _LIBCPP_VERSION -# ifdef __cpp_lib_mdspan -# error "__cpp_lib_mdspan should not be defined because it is unimplemented in libc++!" -# endif +# ifndef __cpp_lib_mdspan +# error "__cpp_lib_mdspan should be defined in c++23" +# endif +# if __cpp_lib_mdspan != 202207L +# error "__cpp_lib_mdspan should have the value 202207L in c++23" # endif # ifdef __cpp_lib_submdspan @@ -84,17 +78,11 @@ #elif TEST_STD_VER > 23 -# if !defined(_LIBCPP_VERSION) -# ifndef __cpp_lib_mdspan -# error "__cpp_lib_mdspan should be defined in c++26" -# endif -# if __cpp_lib_mdspan != 202207L -# error "__cpp_lib_mdspan should have the value 202207L in c++26" -# endif -# else // _LIBCPP_VERSION -# ifdef __cpp_lib_mdspan -# error "__cpp_lib_mdspan should not be defined because it is unimplemented in libc++!" -# endif +# ifndef __cpp_lib_mdspan +# error "__cpp_lib_mdspan should be defined in c++26" +# endif +# if __cpp_lib_mdspan != 202207L +# error "__cpp_lib_mdspan should have the value 202207L in c++26" # endif # if !defined(_LIBCPP_VERSION) Index: libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp =================================================================== --- libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp +++ libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp @@ -4803,17 +4803,11 @@ # endif # endif -# if !defined(_LIBCPP_VERSION) -# ifndef __cpp_lib_mdspan -# error "__cpp_lib_mdspan should be defined in c++23" -# endif -# if __cpp_lib_mdspan != 202207L -# error "__cpp_lib_mdspan should have the value 202207L in c++23" -# endif -# else // _LIBCPP_VERSION -# ifdef __cpp_lib_mdspan -# error "__cpp_lib_mdspan should not be defined because it is unimplemented in libc++!" -# endif +# ifndef __cpp_lib_mdspan +# error "__cpp_lib_mdspan should be defined in c++23" +# endif +# if __cpp_lib_mdspan != 202207L +# error "__cpp_lib_mdspan should have the value 202207L in c++23" # endif # if !defined(_LIBCPP_AVAILABILITY_HAS_NO_PMR) @@ -6356,17 +6350,11 @@ # endif # endif -# if !defined(_LIBCPP_VERSION) -# ifndef __cpp_lib_mdspan -# error "__cpp_lib_mdspan should be defined in c++26" -# endif -# if __cpp_lib_mdspan != 202207L -# error "__cpp_lib_mdspan should have the value 202207L in c++26" -# endif -# else // _LIBCPP_VERSION -# ifdef __cpp_lib_mdspan -# error "__cpp_lib_mdspan should not be defined because it is unimplemented in libc++!" -# endif +# ifndef __cpp_lib_mdspan +# error "__cpp_lib_mdspan should be defined in c++26" +# endif +# if __cpp_lib_mdspan != 202207L +# error "__cpp_lib_mdspan should have the value 202207L in c++26" # endif # if !defined(_LIBCPP_AVAILABILITY_HAS_NO_PMR) Index: libcxx/utils/generate_feature_test_macro_components.py =================================================================== --- libcxx/utils/generate_feature_test_macro_components.py +++ libcxx/utils/generate_feature_test_macro_components.py @@ -691,7 +691,6 @@ "name": "__cpp_lib_mdspan", "values": {"c++23": 202207}, "headers": ["mdspan"], - "unimplemented": True, }, { "name": "__cpp_lib_memory_resource",