Index: libcxx/docs/Status/Cxx23.rst =================================================================== --- libcxx/docs/Status/Cxx23.rst +++ libcxx/docs/Status/Cxx23.rst @@ -40,6 +40,7 @@ .. note:: + .. [#note-P0009R18] P0009R18: ``extents``, ``dextents``, ``layout_left``, and ``layout_right`` 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|","" +"`P0009R18 `__","LWG","mdspan: A Non-Owning Multidimensional Array Reference","July 2022","|In progress| [#note-P0009R18]_|","" "`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 @@ -418,6 +418,7 @@ __fwd/hash.h __fwd/ios.h __fwd/istream.h + __fwd/mdspan.h __fwd/memory_resource.h __fwd/ostream.h __fwd/pair.h @@ -477,6 +478,8 @@ __locale_dir/locale_base_api/locale_guard.h __mbstate_t.h __mdspan/extents.h + __mdspan/layout_left.h + __mdspan/layout_right.h __memory/addressof.h __memory/align.h __memory/aligned_alloc.h Index: libcxx/include/__fwd/mdspan.h =================================================================== --- /dev/null +++ libcxx/include/__fwd/mdspan.h @@ -0,0 +1,60 @@ +// -*- 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_LAYOUTS_H +#define _LIBCPP___MDSPAN_LAYOUTS_H + +#include <__config> + +#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 + +// Layout policy with a mapping which corresponds to FORTRAN-style array layouts +struct layout_left { + template + class mapping; +}; + +// Layout policy with a mapping which corresponds to C-style array layouts +struct layout_right { + template + 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; +}; +*/ + +#endif // _LIBCPP_STD_VER >= 23 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___MDSPAN_LAYOUTS_H Index: libcxx/include/__mdspan/extents.h =================================================================== --- libcxx/include/__mdspan/extents.h +++ libcxx/include/__mdspan/extents.h @@ -220,7 +220,7 @@ // value must be a positive integer otherwise returns false // if _From is not an integral, we just check positivity template - requires(is_integral_v<_From>) + requires(integral<_From>) _LIBCPP_HIDE_FROM_ABI constexpr bool __is_representable_as(_From __value) { using _To_u = make_unsigned_t<_To>; using _From_u = make_unsigned_t<_From>; @@ -236,7 +236,7 @@ } template - requires(!is_integral_v<_From>) + requires(!integral<_From>) _LIBCPP_HIDE_FROM_ABI constexpr bool __is_representable_as(_From __value) { if constexpr (is_signed_v<_To>) { if (static_cast<_To>(__value) < 0) @@ -437,9 +437,9 @@ template extents(_IndexTypes...) -> extents; -// Helper type traits for identifying a class as extents. namespace __mdspan_detail { +// Helper type traits for identifying a class as extents. template struct __is_extents : false_type {}; @@ -449,6 +449,44 @@ template inline constexpr bool __is_extents_v = __is_extents<_Tp>::value; +// Function to check whether a set of indices are a multidimensional +// index into extents. This is a word of power in the C++ standard +// requiring that the indices are larger than 0 and smaller than +// the respective extents. + +template + requires(integral<_From>) +_LIBCPP_HIDE_FROM_ABI constexpr bool __is_index_in_extent(_IndexType __extent, _From __value) { + if constexpr (is_signed_v<_From>) { + if (__value < 0) + return false; + } + using _Tp = common_type_t<_IndexType, _From>; + return static_cast<_Tp>(__value) < static_cast<_Tp>(__extent); +} + +template + requires(!integral<_From>) +_LIBCPP_HIDE_FROM_ABI constexpr bool __is_index_in_extent(_IndexType __extent, _From __value) { + if constexpr (is_signed_v<_IndexType>) { + if (static_cast<_IndexType>(__value) < 0) + return false; + } + return static_cast<_IndexType>(__value) < __extent; +} + +template +_LIBCPP_HIDE_FROM_ABI constexpr bool +__is_multidimensional_index_in_impl(index_sequence<_Idxs...>, const _Extents& __ext, _From... __values) { + return (__mdspan_detail::__is_index_in_extent(__ext.extent(_Idxs), __values) && ...); +} + +template +_LIBCPP_HIDE_FROM_ABI constexpr bool __is_multidimensional_index_in(const _Extents& __ext, _From... __values) { + return __mdspan_detail::__is_multidimensional_index_in_impl( + make_index_sequence<_Extents::rank()>(), __ext, __values...); +} + } // namespace __mdspan_detail #endif // _LIBCPP_STD_VER >= 23 Index: libcxx/include/__mdspan/layout_left.h =================================================================== --- /dev/null +++ libcxx/include/__mdspan/layout_left.h @@ -0,0 +1,169 @@ +// -*- 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_LEFT_H +#define _LIBCPP___MDSPAN_LAYOUT_LEFT_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/integer_sequence.h> +#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 + +template +class layout_left::mapping { +public: + static_assert(__mdspan_detail::__is_extents<_Extents>::value, + "layout_left::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_left; + +private: + _LIBCPP_HIDE_FROM_ABI static constexpr bool __required_span_size_is_representable(const extents_type& __ext) { + if constexpr (extents_type::rank() == 0) + return true; + + index_type __prod = __ext.extent(0); + for (rank_type __r = 1; __r < extents_type::rank(); __r++) { + bool __overflowed = __builtin_mul_overflow(__prod, __ext.extent(__r), &__prod); + if (__overflowed) + return false; + } + return true; + } + + static_assert((extents_type::rank_dynamic() > 0) || __required_span_size_is_representable(extents_type()), + "layout_left::mapping product of static extents must be representable as index_type."); + +public: + // [mdspan.layout.right.cons], constructors + _LIBCPP_HIDE_FROM_ABI constexpr mapping() noexcept = default; + _LIBCPP_HIDE_FROM_ABI constexpr mapping(const mapping&) noexcept = default; + _LIBCPP_HIDE_FROM_ABI constexpr mapping(const extents_type& __ext) noexcept : __extents_(__ext) { + _LIBCPP_ASSERT(__required_span_size_is_representable(__ext), + "layout_left::mapping extents ctor: product of extents must be representable as index_type."); + } + + template + requires(is_constructible_v) + _LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<_OtherExtents, extents_type>) + mapping(const mapping<_OtherExtents>& __other) noexcept + : __extents_(__other.extents()) { + _LIBCPP_ASSERT( + __mdspan_detail::__is_representable_as(__other.required_span_size()), + "layout_left::mapping converting ctor: other.required_span_size() must be representable as index_type."); + } + + template + requires(is_constructible_v && _OtherExtents::rank() <= 1) + _LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<_OtherExtents, extents_type>) + mapping(const layout_right::mapping<_OtherExtents>& __other) noexcept + : __extents_(__other.extents()) { + _LIBCPP_ASSERT( + __mdspan_detail::__is_representable_as(__other.required_span_size()), + "layout_right::mapping converting ctor: other.required_span_size() must be representable as index_type."); + } + +// FIXME: add when we add other layouts +# if 0 + template + constexpr explicit(extents_type::rank() > 0) + mapping(const layout_stride::mapping_&) noexcept; +# endif + + _LIBCPP_HIDE_FROM_ABI constexpr mapping& operator=(const mapping&) noexcept = default; + + // [mdspan.layout.right.obs], observers + _LIBCPP_HIDE_FROM_ABI constexpr const extents_type& extents() const noexcept { return __extents_; } + + _LIBCPP_HIDE_FROM_ABI constexpr index_type required_span_size() const noexcept { + index_type __size = 1; + for (size_t __r = 0; __r < extents_type::rank(); __r++) + __size *= __extents_.extent(__r); + return __size; + } + + template + requires((sizeof...(_Indices) == extents_type::rank()) && (is_convertible_v<_Indices, index_type> && ...) && + (is_nothrow_constructible_v && ...)) + _LIBCPP_HIDE_FROM_ABI constexpr index_type operator()(_Indices... __idx) const noexcept { + _LIBCPP_ASSERT(__mdspan_detail::__is_multidimensional_index_in(__extents_, __idx...), + "layout_left::mapping: out of bounds indexing"); + array __idx_a{static_cast(__idx)...}; + return [&](index_sequence<_Pos...>) { + index_type __res = 0; + ((__res = __idx_a[extents_type::rank()-1-_Pos] + __extents_.extent(extents_type::rank()-1-_Pos) * __res), ...); + return __res; + }(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 true; } + _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; } + _LIBCPP_HIDE_FROM_ABI static constexpr bool is_exhaustive() noexcept { return true; } + _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(extents_type::rank() > 0) + { + _LIBCPP_ASSERT(__r < extents_type::rank(), "layout_left::mapping::stride(): invalid rank index"); + index_type __s = 1; + for (rank_type __i = extents_type::rank() - 1; __i > __r; __i--) + __s *= __extents_.extent(__i); + return __s; + } + + template + requires(_OtherExtents::rank() == extents_type::rank()) + _LIBCPP_HIDE_FROM_ABI friend constexpr bool + operator==(const mapping& __lhs, const mapping<_OtherExtents>& __rhs) noexcept { + return __lhs.extents() == __rhs.extents(); + } + +private: + extents_type __extents_{}; // exposition only +}; + +#endif // _LIBCPP_STD_VER >= 23 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___MDSPAN_LAYOUT_LEFT_H Index: libcxx/include/__mdspan/layout_right.h =================================================================== --- /dev/null +++ libcxx/include/__mdspan/layout_right.h @@ -0,0 +1,168 @@ +// -*- 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_RIGHT_H +#define _LIBCPP___MDSPAN_LAYOUT_RIGHT_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/integer_sequence.h> +#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 + +template +class layout_right::mapping { +public: + static_assert(__mdspan_detail::__is_extents<_Extents>::value, + "layout_right::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_right; + +private: + _LIBCPP_HIDE_FROM_ABI static constexpr bool __required_span_size_is_representable(const extents_type& __ext) { + if constexpr (extents_type::rank() == 0) + return true; + + index_type __prod = __ext.extent(0); + for (rank_type __r = 1; __r < extents_type::rank(); __r++) { + bool __overflowed = __builtin_mul_overflow(__prod, __ext.extent(__r), &__prod); + if (__overflowed) + return false; + } + return true; + } + + static_assert((extents_type::rank_dynamic() > 0) || __required_span_size_is_representable(extents_type()), + "layout_right::mapping product of static extents must be representable as index_type."); + +public: + // [mdspan.layout.right.cons], constructors + _LIBCPP_HIDE_FROM_ABI constexpr mapping() noexcept = default; + _LIBCPP_HIDE_FROM_ABI constexpr mapping(const mapping&) noexcept = default; + _LIBCPP_HIDE_FROM_ABI constexpr mapping(const extents_type& __ext) noexcept : __extents_(__ext) { + _LIBCPP_ASSERT(__required_span_size_is_representable(__ext), + "layout_right::mapping extents ctor: product of extents must be representable as index_type."); + } + + template + requires(is_constructible_v) + _LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<_OtherExtents, extents_type>) + mapping(const mapping<_OtherExtents>& __other) noexcept + : __extents_(__other.extents()) { + _LIBCPP_ASSERT( + __mdspan_detail::__is_representable_as(__other.required_span_size()), + "layout_right::mapping converting ctor: other.required_span_size() must be representable as index_type."); + } + + template + requires(is_constructible_v && _OtherExtents::rank() <= 1) + _LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<_OtherExtents, extents_type>) + mapping(const layout_left::mapping<_OtherExtents>& __other) noexcept + : __extents_(__other.extents()) { + _LIBCPP_ASSERT( + __mdspan_detail::__is_representable_as(__other.required_span_size()), + "layout_right::mapping converting ctor: other.required_span_size() must be representable as index_type."); + } + +// FIXME: add when we add other layouts +# if 0 + template + constexpr explicit(extents_type::rank() > 0) + mapping(const layout_stride::mapping_&) noexcept; +# endif + + _LIBCPP_HIDE_FROM_ABI constexpr mapping& operator=(const mapping&) noexcept = default; + + // [mdspan.layout.right.obs], observers + _LIBCPP_HIDE_FROM_ABI constexpr const extents_type& extents() const noexcept { return __extents_; } + + _LIBCPP_HIDE_FROM_ABI constexpr index_type required_span_size() const noexcept { + index_type __size = 1; + for (size_t __r = 0; __r < extents_type::rank(); __r++) + __size *= __extents_.extent(__r); + return __size; + } + + template + requires((sizeof...(_Indices) == extents_type::rank()) && (is_convertible_v<_Indices, index_type> && ...) && + (is_nothrow_constructible_v && ...)) + _LIBCPP_HIDE_FROM_ABI constexpr index_type operator()(_Indices... __idx) const noexcept { + _LIBCPP_ASSERT(__mdspan_detail::__is_multidimensional_index_in(__extents_, __idx...), + "layout_right::mapping: out of bounds indexing"); + return [&](index_sequence<_Pos...>) { + index_type __res = 0; + ((__res = static_cast(__idx) + __extents_.extent(_Pos) * __res), ...); + return __res; + }(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 true; } + _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; } + _LIBCPP_HIDE_FROM_ABI static constexpr bool is_exhaustive() noexcept { return true; } + _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(extents_type::rank() > 0) + { + _LIBCPP_ASSERT(__r < extents_type::rank(), "layout_right::mapping::stride(): invalid rank index"); + index_type __s = 1; + for (rank_type __i = extents_type::rank() - 1; __i > __r; __i--) + __s *= __extents_.extent(__i); + return __s; + } + + template + requires(_OtherExtents::rank() == extents_type::rank()) + _LIBCPP_HIDE_FROM_ABI friend constexpr bool + operator==(const mapping& __lhs, const mapping<_OtherExtents>& __rhs) noexcept { + return __lhs.extents() == __rhs.extents(); + } + +private: + extents_type __extents_{}; // exposition only +}; + +#endif // _LIBCPP_STD_VER >= 23 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___MDSPAN_LAYOUT_RIGHT_H Index: libcxx/include/mdspan =================================================================== --- libcxx/include/mdspan +++ libcxx/include/mdspan @@ -8,7 +8,34 @@ //===---------------------------------------------------------------------===// /* - extents synopsis + +// Overall mdspan synopsis + +namespace std { + // [mdspan.extents], class template extents + template + class extents; + + // [mdspan.extents.dextents], alias template dextents + template + using dextents = see below; + + // [mdspan.layout], layout mapping + struct layout_left; + struct layout_right; + struct layout_stride; // not implemented yet + + // [mdspan.accessor.default], class template default_accessor + template + class default_accessor; // not implemented yet + + // [mdspan.mdspan], class template mdspan + template> + class mdspan; // not implemented yet +} + +// extents synopsis namespace std { template @@ -54,13 +81,125 @@ explicit extents(Integrals...) -> see below; } + +// layout_left synopsis + +namespace std { + template + class layout_left::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_left; + + // [mdspan.layout.right.cons], constructors + constexpr mapping() noexcept = default; + constexpr mapping(const mapping&) noexcept = default; + constexpr mapping(const extents_type&) noexcept; + template + constexpr explicit(!is_convertible_v) + mapping(const mapping&) noexcept; + template + constexpr explicit(!is_convertible_v) + mapping(const layout_right::mapping&) noexcept; + template + constexpr explicit(extents_type::rank() > 0) + mapping(const layout_stride::mapping&) noexcept; + + constexpr mapping& operator=(const mapping&) noexcept = default; + + // [mdspan.layout.right.obs], observers + constexpr const extents_type& extents() const noexcept { return extents_; } + + 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 true; } + 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; } + static constexpr bool is_strided() noexcept { return true; } + + constexpr index_type stride(rank_type) const noexcept; + + template + friend constexpr bool operator==(const mapping&, const mapping&) noexcept; + + private: + extents_type extents_{}; // exposition only + }; +} + +// layout_right synopsis + +namespace std { + template + class layout_right::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_right; + + // [mdspan.layout.right.cons], constructors + constexpr mapping() noexcept = default; + constexpr mapping(const mapping&) noexcept = default; + constexpr mapping(const extents_type&) noexcept; + template + constexpr explicit(!is_convertible_v) + mapping(const mapping&) noexcept; + template + constexpr explicit(!is_convertible_v) + mapping(const layout_left::mapping&) noexcept; + template + constexpr explicit(extents_type::rank() > 0) + mapping(const layout_stride::mapping&) noexcept; + + constexpr mapping& operator=(const mapping&) noexcept = default; + + // [mdspan.layout.right.obs], observers + constexpr const extents_type& extents() const noexcept { return extents_; } + + 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 true; } + 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; } + static constexpr bool is_strided() noexcept { return true; } + + constexpr index_type stride(rank_type) const noexcept; + + template + friend constexpr bool operator==(const mapping&, const mapping&) noexcept; + + private: + extents_type extents_{}; // exposition only + }; +} + */ #ifndef _LIBCPP_MDSPAN #define _LIBCPP_MDSPAN #include <__config> +#include <__fwd/mdspan.h> #include <__mdspan/extents.h> +#include <__mdspan/layout_left.h> +#include <__mdspan/layout_right.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header Index: libcxx/include/module.modulemap.in =================================================================== --- libcxx/include/module.modulemap.in +++ libcxx/include/module.modulemap.in @@ -1173,6 +1173,9 @@ module __mdspan { module extents { private header "__mdspan/extents.h" } + module layout_left { private header "__mdspan/layout_left.h" } + module layout_right { private header "__mdspan/layout_right.h" } + module mdspan_fwd { private header "__fwd/mdspan.h" } } } module memory { Index: libcxx/modules/std/mdspan.cppm =================================================================== --- libcxx/modules/std/mdspan.cppm +++ libcxx/modules/std/mdspan.cppm @@ -18,12 +18,12 @@ // [mdspan.extents.dextents], alias template dextents using std::dextents; -#if 0 // [mdspan.layout], layout mapping using std::layout_left; using std::layout_right; - using std::layout_stride; + // using std::layout_stride; +#if 0 // [mdspan.accessor.default], class template default_­accessor using std::default_accessor; Index: libcxx/test/std/containers/views/mdspan/layout_left/assert.conversion.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/containers/views/mdspan/layout_left/assert.conversion.pass.cpp @@ -0,0 +1,51 @@ +// +// 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 +// XFAIL: availability-verbose_abort-missing +// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1 + +// + +// template +// constexpr explicit(!is_convertible_v) +// mapping(const mapping&) noexcept; + +// Constraints: is_constructible_v is true. +// +// Preconditions: other.required_span_size() is representable as a value of type index_type. + +#include +#include + +#include "check_assertion.h" + +int main(int, char**) { + constexpr size_t D = std::dynamic_extent; + std::extents arg_exts{100, 5}; + std::layout_left::mapping> arg(arg_exts); + + // working case + { + [[maybe_unused]] std::layout_left::mapping> m(arg); // should work + } + // mismatch of static extent + { + TEST_LIBCPP_ASSERT_FAILURE(([=] { std::layout_left::mapping> m(arg); }()), + "extents construction: mismatch of provided arguments with static extents."); + } + // value out of range + { + // 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_left + TEST_LIBCPP_ASSERT_FAILURE( + ([=] { std::layout_left::template mapping> m(arg); }()), + "layout_left::mapping converting ctor: other.required_span_size() must be representable as index_type."); + } + return 0; +} Index: libcxx/test/std/containers/views/mdspan/layout_left/assert.ctor.extents.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/containers/views/mdspan/layout_left/assert.ctor.extents.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 +// XFAIL: availability-verbose_abort-missing +// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1 + +// + + +// constexpr mapping(const extents_type& e) noexcept; +// +// Preconditions: The size of the multidimensional index space e is representable as a value of type index_type ([basic.fundamental]). +// +// Effects: Direct-non-list-initializes extents_ with e. + +#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 is not, so we can't use it for layout_left + TEST_LIBCPP_ASSERT_FAILURE( + ([=] { std::layout_left::template mapping> m(std::extents(100)); }()), + "layout_left::mapping extents ctor: product of extents must be representable as index_type."); + } + return 0; +} Index: libcxx/test/std/containers/views/mdspan/layout_left/assert.ctor.layout_right.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/containers/views/mdspan/layout_left/assert.ctor.layout_right.pass.cpp @@ -0,0 +1,44 @@ +// +// 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 +// XFAIL: availability-verbose_abort-missing +// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1 + +// + +// template +// constexpr explicit(!is_convertible_v) +// mapping(const layout_right::mapping&) noexcept; + +// Constraints: +// - extents_type::rank() <= 1 is true, and +// - is_constructible_v is true. +// +// Preconditions: other.required_span_size() is representable as a value of type index_type + +#include +#include + +#include "check_assertion.h" + +int main(int, char**) { + constexpr size_t D = std::dynamic_extent; + std::extents arg_exts{5}; + std::layout_right::mapping> arg(arg_exts); + + // working case + { + [[maybe_unused]] std::layout_left::mapping> m(arg); // should work + } + // mismatch of static extent + { + TEST_LIBCPP_ASSERT_FAILURE(([=] { std::layout_left::mapping> m(arg); }()), + "extents construction: mismatch of provided arguments with static extents."); + } + return 0; +} Index: libcxx/test/std/containers/views/mdspan/layout_left/assert.index_operator.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/containers/views/mdspan/layout_left/assert.index_operator.pass.cpp @@ -0,0 +1,82 @@ +// +// 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 +// XFAIL: availability-verbose_abort-missing +// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1 + +// + +// 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_left::template mapping> m; + TEST_LIBCPP_ASSERT_FAILURE(m(-1), "layout_left::mapping: out of bounds indexing"); + TEST_LIBCPP_ASSERT_FAILURE(m(-130), "layout_left::mapping: out of bounds indexing"); + TEST_LIBCPP_ASSERT_FAILURE(m(5), "layout_left::mapping: out of bounds indexing"); + TEST_LIBCPP_ASSERT_FAILURE(m(1000), "layout_left::mapping: out of bounds indexing"); + } + { + std::layout_left::template mapping> m; + TEST_LIBCPP_ASSERT_FAILURE(m(-1), "layout_left::mapping: out of bounds indexing"); + TEST_LIBCPP_ASSERT_FAILURE(m(-130), "layout_left::mapping: out of bounds indexing"); + TEST_LIBCPP_ASSERT_FAILURE(m(5), "layout_left::mapping: out of bounds indexing"); + TEST_LIBCPP_ASSERT_FAILURE(m(1000), "layout_left::mapping: out of bounds indexing"); + } + { + std::layout_left::template mapping> m(std::dextents(5)); + TEST_LIBCPP_ASSERT_FAILURE(m(-1), "layout_left::mapping: out of bounds indexing"); + TEST_LIBCPP_ASSERT_FAILURE(m(-130), "layout_left::mapping: out of bounds indexing"); + TEST_LIBCPP_ASSERT_FAILURE(m(5), "layout_left::mapping: out of bounds indexing"); + TEST_LIBCPP_ASSERT_FAILURE(m(1000), "layout_left::mapping: out of bounds indexing"); + } + { + std::layout_left::template mapping> m(std::dextents(5)); + TEST_LIBCPP_ASSERT_FAILURE(m(-1), "layout_left::mapping: out of bounds indexing"); + TEST_LIBCPP_ASSERT_FAILURE(m(-130), "layout_left::mapping: out of bounds indexing"); + TEST_LIBCPP_ASSERT_FAILURE(m(5), "layout_left::mapping: out of bounds indexing"); + TEST_LIBCPP_ASSERT_FAILURE(m(1000), "layout_left::mapping: out of bounds indexing"); + } + { + std::layout_left::template mapping> m(std::dextents(5, 7, 9)); + TEST_LIBCPP_ASSERT_FAILURE(m(-1, -1, -1), "layout_left::mapping: out of bounds indexing"); + TEST_LIBCPP_ASSERT_FAILURE(m(-1, 0, 0), "layout_left::mapping: out of bounds indexing"); + TEST_LIBCPP_ASSERT_FAILURE(m(0, -1, 0), "layout_left::mapping: out of bounds indexing"); + TEST_LIBCPP_ASSERT_FAILURE(m(0, 0, -1), "layout_left::mapping: out of bounds indexing"); + TEST_LIBCPP_ASSERT_FAILURE(m(5, 3, 3), "layout_left::mapping: out of bounds indexing"); + TEST_LIBCPP_ASSERT_FAILURE(m(3, 7, 3), "layout_left::mapping: out of bounds indexing"); + TEST_LIBCPP_ASSERT_FAILURE(m(3, 3, 9), "layout_left::mapping: out of bounds indexing"); + TEST_LIBCPP_ASSERT_FAILURE(m(5, 7, 9), "layout_left::mapping: out of bounds indexing"); + } + { + std::layout_left::template mapping> m(std::dextents(5, 7, 9)); + TEST_LIBCPP_ASSERT_FAILURE(m(-1, -1, -1), "layout_left::mapping: out of bounds indexing"); + TEST_LIBCPP_ASSERT_FAILURE(m(-1, 0, 0), "layout_left::mapping: out of bounds indexing"); + TEST_LIBCPP_ASSERT_FAILURE(m(0, -1, 0), "layout_left::mapping: out of bounds indexing"); + TEST_LIBCPP_ASSERT_FAILURE(m(0, 0, -1), "layout_left::mapping: out of bounds indexing"); + TEST_LIBCPP_ASSERT_FAILURE(m(5, 3, 3), "layout_left::mapping: out of bounds indexing"); + TEST_LIBCPP_ASSERT_FAILURE(m(3, 7, 3), "layout_left::mapping: out of bounds indexing"); + TEST_LIBCPP_ASSERT_FAILURE(m(3, 3, 9), "layout_left::mapping: out of bounds indexing"); + TEST_LIBCPP_ASSERT_FAILURE(m(5, 7, 9), "layout_left::mapping: out of bounds indexing"); + } + return 0; +} Index: libcxx/test/std/containers/views/mdspan/layout_left/assert.stride.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/containers/views/mdspan/layout_left/assert.stride.pass.cpp @@ -0,0 +1,39 @@ +// +// 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 +// XFAIL: availability-verbose_abort-missing +// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1 + +// + +// layout_left::mapping +// +// 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 "check_assertion.h" + +int main(int, char**) { + // value out of range + { + std::layout_left::template mapping> m{std::dextents{100, 100, 100}}; + + TEST_LIBCPP_ASSERT_FAILURE(m.stride(4), "invalid rank index"); + } + return 0; +} Index: libcxx/test/std/containers/views/mdspan/layout_left/comparison.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/containers/views/mdspan/layout_left/comparison.pass.cpp @@ -0,0 +1,113 @@ +//===----------------------------------------------------------------------===// +// +// 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 mapping& y) noexcept; +// ` +// Constraints: extents_type::rank() == OtherExtents::rank() is true. + +#include +#include +#include +#include + +#include "test_macros.h" + +template +constexpr void test_comparison(bool equal, To dest_exts, From src_exts) { + std::layout_left::mapping dest(dest_exts); + std::layout_left::mapping src(src_exts); + 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, E2 e2) + -> decltype(std::layout_left::mapping(e1) == std::layout_left::mapping(e2)) { + return true; +} + +template +constexpr void test_comparison_different_rank() { + constexpr size_t D = std::dynamic_extent; + + // sanity check same rank + static_assert(compare_layout_mappings(std::extents(5), std::extents(5))); + static_assert(compare_layout_mappings(std::extents(), std::extents(5))); + static_assert(compare_layout_mappings(std::extents(5), std::extents())); + static_assert(compare_layout_mappings(std::extents(), std::extents())); + + // not equality comparable when rank is not the same + static_assert(compare_layout_mappings(std::extents(), std::extents(1)).does_not_match()); + static_assert(compare_layout_mappings(std::extents(), std::extents()).does_not_match()); + + static_assert(compare_layout_mappings(std::extents(1), std::extents()).does_not_match()); + static_assert(compare_layout_mappings(std::extents(), std::extents()).does_not_match()); + + static_assert(compare_layout_mappings(std::extents(5), std::extents(5, 5)).does_not_match()); + static_assert(compare_layout_mappings(std::extents(), std::extents(5)).does_not_match()); + static_assert(compare_layout_mappings(std::extents(), std::extents()).does_not_match()); + + static_assert(compare_layout_mappings(std::extents(5, 5), std::extents(5)).does_not_match()); + static_assert(compare_layout_mappings(std::extents(5), std::extents(5)).does_not_match()); + static_assert(compare_layout_mappings(std::extents(), std::extents()).does_not_match()); +} + +template +constexpr void test_comparison_same_rank() { + constexpr size_t D = std::dynamic_extent; + + test_comparison(true, std::extents(), std::extents()); + + test_comparison(true, std::extents(5), std::extents(5)); + test_comparison(true, std::extents(), std::extents(5)); + test_comparison(true, std::extents(5), std::extents()); + test_comparison(true, std::extents(), std::extents< T2, 5>()); + test_comparison(false, std::extents(5), std::extents(7)); + test_comparison(false, std::extents(), std::extents(7)); + test_comparison(false, std::extents(5), std::extents()); + test_comparison(false, std::extents(), std::extents()); + + test_comparison(true, std::extents(5, 6, 7, 8, 9), std::extents(5, 6, 7, 8, 9)); + test_comparison(true, std::extents(5, 7, 9), std::extents(6, 7)); + test_comparison(true, std::extents(5, 6, 7, 8, 9), std::extents()); + test_comparison( + false, std::extents(5, 6, 7, 8, 9), std::extents(5, 6, 3, 8, 9)); + test_comparison(false, std::extents(5, 7, 9), std::extents(6, 7)); + test_comparison(false, std::extents(5, 6, 7, 8, 9), std::extents()); +} + +template +constexpr void test_comparison() { + test_comparison_same_rank(); + test_comparison_different_rank(); +} + +constexpr bool test() { + test_comparison(); + test_comparison(); + test_comparison(); + test_comparison(); + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + return 0; +} Index: libcxx/test/std/containers/views/mdspan/layout_left/ctor.default.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/containers/views/mdspan/layout_left/ctor.default.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 + +// + +// Test default construction: +// +// constexpr mapping() noexcept = default; + +#include +#include +#include + +#include "test_macros.h" + +template +constexpr void test_construction() { + using M = std::layout_left::mapping; + ASSERT_NOEXCEPT(M{}); + M m; + E e; + + // check correct extents are returned + ASSERT_NOEXCEPT(m.extents()); + assert(m.extents() == e); + + // NOTE should we be passing it in instead + // 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_NOEXCEPT(m.required_span_size()); + assert(m.required_span_size() == expected_size); +} + +constexpr bool test() { + constexpr size_t D = std::dynamic_extent; + 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_left/ctor.extents.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/containers/views/mdspan/layout_left/ctor.extents.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 mapping(const extents_type&) noexcept; +// +// Preconditions: The size of the multidimensional index space e is representable +// as a value of type index_type ([basic.fundamental]). +// +// Effects: Direct-non-list-initializes extents_ with e. + +#include +#include +#include + +#include "test_macros.h" + +template +constexpr void test_construction(E e) { + using M = std::layout_left::mapping; + ASSERT_NOEXCEPT(M{e}); + M m(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_NOEXCEPT(m.required_span_size()); + assert(m.required_span_size() == expected_size); +} + +constexpr bool test() { + constexpr size_t D = std::dynamic_extent; + test_construction(std::extents()); + test_construction(std::extents(7)); + test_construction(std::extents()); + test_construction(std::extents()); + test_construction(std::extents(7, 9, 10)); + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + return 0; +} Index: libcxx/test/std/containers/views/mdspan/layout_left/ctor.layout_right.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/containers/views/mdspan/layout_left/ctor.layout_right.pass.cpp @@ -0,0 +1,127 @@ +//===----------------------------------------------------------------------===// +// +// 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(!is_convertible_v) +// mapping(const layout_right::mapping&) noexcept; + +// Constraints: +// - extents_type::rank() <= 1 is true, and +// - is_constructible_v is true. +// +// Preconditions: other.required_span_size() is representable as a value of type index_type + +#include +#include +#include // what do we use from there? +#include +#include + +#include "test_macros.h" + +template +constexpr void test_implicit_conversion(To dest, From src) { + assert(dest.extents() == src.extents()); +} + +template +constexpr void test_conversion(FromE src_exts) { + using To = std::layout_left::mapping; + using From = std::layout_right::mapping; + From src(src_exts); + + ASSERT_NOEXCEPT(To(src)); + To dest(src); + + assert(dest.extents() == src.extents()); + if constexpr (implicit) { + dest = src; + assert(dest.extents() == src.extents()); + test_implicit_conversion(src, src); + } +} + +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()); + + // clang-format off + test_conversion>(std::extents()); + test_conversion>(std::extents(5)); + test_conversion>(std::extents(5)); + test_conversion>(std::extents()); + // clang-format on +} + +template +using lr_mapping_t = typename std::layout_right::template mapping>; +template +using ll_mapping_t = typename std::layout_left::template mapping>; + +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, lr_mapping_t>); + static_assert(std::is_convertible_v, ll_mapping_t>); + + // Check that dynamic to static conversion only works explicitly + static_assert(std::is_constructible_v, lr_mapping_t>); + static_assert(!std::is_convertible_v, ll_mapping_t>); + + // Sanity check that smaller index_type to larger index_type conversion works + static_assert(std::is_constructible_v, lr_mapping_t>); + static_assert(std::is_convertible_v, ll_mapping_t>); + + // Check that larger index_type to smaller index_type conversion works explicitly only + static_assert(std::is_constructible_v, lr_mapping_t>); + static_assert(!std::is_convertible_v, ll_mapping_t>); +} + +constexpr void test_rank_mismatch() { + constexpr size_t D = std::dynamic_extent; + + static_assert(!std::is_constructible_v, lr_mapping_t>); + static_assert(!std::is_constructible_v, lr_mapping_t>); + static_assert(!std::is_constructible_v, lr_mapping_t>); + static_assert(!std::is_constructible_v, lr_mapping_t>); +} + +constexpr void test_static_extent_mismatch() { + static_assert(!std::is_constructible_v, lr_mapping_t>); +} + +constexpr void test_rank_greater_one() { + constexpr size_t D = std::dynamic_extent; + + static_assert(!std::is_constructible_v, lr_mapping_t>); + static_assert(!std::is_constructible_v, lr_mapping_t>); +} + +constexpr bool test() { + test_conversion(); + test_conversion(); + test_conversion(); + test_conversion(); + test_no_implicit_conversion(); + test_rank_mismatch(); + test_static_extent_mismatch(); + test_rank_greater_one(); + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + return 0; +} Index: libcxx/test/std/containers/views/mdspan/layout_left/ctor.mapping.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/containers/views/mdspan/layout_left/ctor.mapping.pass.cpp @@ -0,0 +1,136 @@ +//===----------------------------------------------------------------------===// +// +// 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(!is_convertible_v) +// mapping(const mapping&) noexcept; + +// Constraints: is_constructible_v is true. +// +// Preconditions: other.required_span_size() is representable as a value of type index_type + +#include +#include +#include // what do we use from there? +#include +#include + +#include "test_macros.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_left::mapping; + using From = std::layout_left::mapping; + From src(src_exts); + + ASSERT_NOEXCEPT(To(src)); + To dest(src); + + assert(dest == src); + if constexpr (implicit) { + dest = src; + assert(dest == src); + test_implicit_conversion(src, src); + } +} + +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()); + + // clang-format off + 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 mapping_t = typename std::layout_left::template mapping>; + +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, mapping_t>); + static_assert(std::is_convertible_v, mapping_t>); + + // Check that dynamic to static conversion only works explicitly + static_assert(std::is_constructible_v, mapping_t>); + static_assert(!std::is_convertible_v, mapping_t>); + + // Sanity check that one static to dynamic conversion works + static_assert(std::is_constructible_v, mapping_t>); + static_assert(std::is_convertible_v, mapping_t>); + + // Check that dynamic to static conversion only works explicitly + static_assert(std::is_constructible_v, mapping_t>); + static_assert(!std::is_convertible_v, mapping_t>); + + // Sanity check that smaller index_type to larger index_type conversion works + static_assert(std::is_constructible_v, mapping_t>); + static_assert(std::is_convertible_v, mapping_t>); + + // Check that larger index_type to smaller index_type conversion works explicitly only + static_assert(std::is_constructible_v, mapping_t>); + static_assert(!std::is_convertible_v, mapping_t>); +} + +constexpr void test_rank_mismatch() { + constexpr size_t D = std::dynamic_extent; + + static_assert(!std::is_constructible_v, mapping_t>); + static_assert(!std::is_constructible_v, mapping_t>); + static_assert(!std::is_constructible_v, mapping_t>); + static_assert(!std::is_constructible_v, mapping_t>); +} + +constexpr void test_static_extent_mismatch() { + constexpr size_t D = std::dynamic_extent; + + static_assert(!std::is_constructible_v, mapping_t>); + static_assert(!std::is_constructible_v, mapping_t>); + static_assert(!std::is_constructible_v, mapping_t>); +} + +constexpr bool test() { + test_conversion(); + test_conversion(); + test_conversion(); + test_conversion(); + test_no_implicit_conversion(); + test_rank_mismatch(); + test_static_extent_mismatch(); + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + return 0; +} Index: libcxx/test/std/containers/views/mdspan/layout_left/extents.verify.cpp =================================================================== --- /dev/null +++ libcxx/test/std/containers/views/mdspan/layout_left/extents.verify.cpp @@ -0,0 +1,32 @@ +// +// 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 + +// + +// template +// class layout_left::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_left::mapping template argument must be a specialization of extents}} + [[maybe_unused]] std::layout_left::mapping mapping; +} + +void representable() { + // expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}layout_left::mapping product of static extents must be representable as index_type.}} + [[maybe_unused]] std::layout_left::mapping> mapping; +} Index: libcxx/test/std/containers/views/mdspan/layout_left/index_operator.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/containers/views/mdspan/layout_left/index_operator.pass.cpp @@ -0,0 +1,110 @@ +//===----------------------------------------------------------------------===// +// +// 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" + +struct IntType { + int val; + constexpr IntType() = default; + constexpr IntType(int v) noexcept : val(v){}; + + constexpr bool operator==(const IntType& rhs) const { return val == rhs.val; } + constexpr operator int() const noexcept { return val; } + constexpr operator unsigned char() const { return val; } +}; + + +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_left(M m, T& count, Args... args) { + constexpr int r = static_cast(M::extents_type::rank()) - 1 - static_cast(sizeof...(Args)); + if constexpr (-1 == r) { + ASSERT_NOEXCEPT(m(args...)); + assert(count == m(args...)); + count++; + } else { + for (typename M::index_type i = 0; i < m.extents().extent(r); i++) { + iterate_left(m, count, i, args...); + } + } +} + +template +constexpr void test_iteration(Args... args) { + using M = std::layout_left::mapping; + M m(E(args...)); + + typename E::index_type count = 0; + iterate_left(m, count); +} + +constexpr bool test() { + constexpr size_t D = std::dynamic_extent; + test_iteration>(); + test_iteration>(7); + test_iteration>(); + test_iteration>(); + test_iteration>(7, 9, 10); + + // Check operator constraint for number of arguments + static_assert(check_operator_constraints(std::layout_left::mapping>(std::extents(1)), 0)); + static_assert(!check_operator_constraints(std::layout_left::mapping>(std::extents(1)), 0, 0)); + + // Check operator constraint for convertibility of arguments to index_type + static_assert(check_operator_constraints(std::layout_left::mapping>(std::extents(1)), IntType(0))); + static_assert(!check_operator_constraints(std::layout_left::mapping>(std::extents(1)), IntType(0))); + + // Check operator constraint for no-throw-constructibility of index_type from arguments + static_assert(!check_operator_constraints(std::layout_left::mapping>(std::extents(1)), IntType(0))); + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + return 0; +} Index: libcxx/test/std/containers/views/mdspan/layout_left/properties.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/containers/views/mdspan/layout_left/properties.pass.cpp @@ -0,0 +1,65 @@ +//===----------------------------------------------------------------------===// +// +// 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_left::mapping { +// +// ... +// 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 true; } +// +// static constexpr bool is_unique() noexcept { return true; } +// static constexpr bool is_exhaustive() noexcept { return true; } +// static constexpr bool is_strided() noexcept { return true; } +// ... +// }; +// } + +#include +#include +#include +#include + +#include "test_macros.h" + +template +constexpr void test_layout_mapping_right() { + using M = std::layout_left::template mapping; + assert(M::is_unique() == true); + assert(M::is_exhaustive() == true); + assert(M::is_strided() == true); + assert(M::is_always_unique() == true); + assert(M::is_always_exhaustive() == true); + 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()); +} + +constexpr bool test() { + constexpr size_t D = std::dynamic_extent; + test_layout_mapping_right>(); + test_layout_mapping_right>(); + test_layout_mapping_right>(); + test_layout_mapping_right>(); + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + return 0; +} Index: libcxx/test/std/containers/views/mdspan/layout_left/static_requirements.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/containers/views/mdspan/layout_left/static_requirements.pass.cpp @@ -0,0 +1,130 @@ +//===----------------------------------------------------------------------===// +// +// 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_left); + 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()(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_right() { + test_layout_mapping_requirements(); +} + +int main(int, char**) { + constexpr size_t D = std::dynamic_extent; + test_layout_mapping_right>(); + test_layout_mapping_right>(); + test_layout_mapping_right>(); + test_layout_mapping_right>(); + return 0; +} Index: libcxx/test/std/containers/views/mdspan/layout_left/stride.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/containers/views/mdspan/layout_left/stride.pass.cpp @@ -0,0 +1,50 @@ +//===----------------------------------------------------------------------===// +// +// 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_left::mapping; + M m(E(args...)); + + ASSERT_NOEXCEPT(m.stride(0)); + for (size_t r = 0; r < E::rank(); r++) + assert(strides[r] == m.stride(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/layout_right/assert.conversion.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/containers/views/mdspan/layout_right/assert.conversion.pass.cpp @@ -0,0 +1,51 @@ +// +// 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 +// XFAIL: availability-verbose_abort-missing +// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1 + +// + +// template +// constexpr explicit(!is_convertible_v) +// mapping(const mapping&) noexcept; + +// Constraints: is_constructible_v is true. +// +// Preconditions: other.required_span_size() is representable as a value of type index_type. + +#include +#include + +#include "check_assertion.h" + +int main(int, char**) { + constexpr size_t D = std::dynamic_extent; + std::extents arg_exts{100, 5}; + std::layout_right::mapping> arg(arg_exts); + + // working case + { + [[maybe_unused]] std::layout_right::mapping> m(arg); // should work + } + // mismatch of static extent + { + TEST_LIBCPP_ASSERT_FAILURE(([=] { std::layout_right::mapping> m(arg); }()), + "extents construction: mismatch of provided arguments with static extents."); + } + // value out of range + { + // 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_right + TEST_LIBCPP_ASSERT_FAILURE( + ([=] { std::layout_right::template mapping> m(arg); }()), + "layout_right::mapping converting ctor: other.required_span_size() must be representable as index_type."); + } + return 0; +} Index: libcxx/test/std/containers/views/mdspan/layout_right/assert.ctor.extents.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/containers/views/mdspan/layout_right/assert.ctor.extents.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 +// XFAIL: availability-verbose_abort-missing +// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1 + +// + + +// constexpr mapping(const extents_type& e) noexcept; +// +// Preconditions: The size of the multidimensional index space e is representable as a value of type index_type ([basic.fundamental]). +// +// Effects: Direct-non-list-initializes extents_ with e. + +#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 is not, so we can't use it for layout_right + TEST_LIBCPP_ASSERT_FAILURE( + ([=] { std::layout_right::template mapping> m(std::extents(100)); }()), + "layout_right::mapping extents ctor: product of extents must be representable as index_type."); + } + return 0; +} Index: libcxx/test/std/containers/views/mdspan/layout_right/assert.ctor.layout_left.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/containers/views/mdspan/layout_right/assert.ctor.layout_left.pass.cpp @@ -0,0 +1,44 @@ +// +// 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 +// XFAIL: availability-verbose_abort-missing +// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1 + +// + +// template +// constexpr explicit(!is_convertible_v) +// mapping(const layout_left::mapping&) noexcept; + +// Constraints: +// - extents_type::rank() <= 1 is true, and +// - is_constructible_v is true. +// +// Preconditions: other.required_span_size() is representable as a value of type index_type + +#include +#include + +#include "check_assertion.h" + +int main(int, char**) { + constexpr size_t D = std::dynamic_extent; + std::extents arg_exts{5}; + std::layout_left::mapping> arg(arg_exts); + + // working case + { + [[maybe_unused]] std::layout_right::mapping> m(arg); // should work + } + // mismatch of static extent + { + TEST_LIBCPP_ASSERT_FAILURE(([=] { std::layout_right::mapping> m(arg); }()), + "extents construction: mismatch of provided arguments with static extents."); + } + return 0; +} Index: libcxx/test/std/containers/views/mdspan/layout_right/assert.index_operator.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/containers/views/mdspan/layout_right/assert.index_operator.pass.cpp @@ -0,0 +1,82 @@ +// +// 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 +// XFAIL: availability-verbose_abort-missing +// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1 + +// + +// 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_right::template mapping> m; + TEST_LIBCPP_ASSERT_FAILURE(m(-1), "layout_right::mapping: out of bounds indexing"); + TEST_LIBCPP_ASSERT_FAILURE(m(-130), "layout_right::mapping: out of bounds indexing"); + TEST_LIBCPP_ASSERT_FAILURE(m(5), "layout_right::mapping: out of bounds indexing"); + TEST_LIBCPP_ASSERT_FAILURE(m(1000), "layout_right::mapping: out of bounds indexing"); + } + { + std::layout_right::template mapping> m; + TEST_LIBCPP_ASSERT_FAILURE(m(-1), "layout_right::mapping: out of bounds indexing"); + TEST_LIBCPP_ASSERT_FAILURE(m(-130), "layout_right::mapping: out of bounds indexing"); + TEST_LIBCPP_ASSERT_FAILURE(m(5), "layout_right::mapping: out of bounds indexing"); + TEST_LIBCPP_ASSERT_FAILURE(m(1000), "layout_right::mapping: out of bounds indexing"); + } + { + std::layout_right::template mapping> m(std::dextents(5)); + TEST_LIBCPP_ASSERT_FAILURE(m(-1), "layout_right::mapping: out of bounds indexing"); + TEST_LIBCPP_ASSERT_FAILURE(m(-130), "layout_right::mapping: out of bounds indexing"); + TEST_LIBCPP_ASSERT_FAILURE(m(5), "layout_right::mapping: out of bounds indexing"); + TEST_LIBCPP_ASSERT_FAILURE(m(1000), "layout_right::mapping: out of bounds indexing"); + } + { + std::layout_right::template mapping> m(std::dextents(5)); + TEST_LIBCPP_ASSERT_FAILURE(m(-1), "layout_right::mapping: out of bounds indexing"); + TEST_LIBCPP_ASSERT_FAILURE(m(-130), "layout_right::mapping: out of bounds indexing"); + TEST_LIBCPP_ASSERT_FAILURE(m(5), "layout_right::mapping: out of bounds indexing"); + TEST_LIBCPP_ASSERT_FAILURE(m(1000), "layout_right::mapping: out of bounds indexing"); + } + { + std::layout_right::template mapping> m(std::dextents(5, 7, 9)); + TEST_LIBCPP_ASSERT_FAILURE(m(-1, -1, -1), "layout_right::mapping: out of bounds indexing"); + TEST_LIBCPP_ASSERT_FAILURE(m(-1, 0, 0), "layout_right::mapping: out of bounds indexing"); + TEST_LIBCPP_ASSERT_FAILURE(m(0, -1, 0), "layout_right::mapping: out of bounds indexing"); + TEST_LIBCPP_ASSERT_FAILURE(m(0, 0, -1), "layout_right::mapping: out of bounds indexing"); + TEST_LIBCPP_ASSERT_FAILURE(m(5, 3, 3), "layout_right::mapping: out of bounds indexing"); + TEST_LIBCPP_ASSERT_FAILURE(m(3, 7, 3), "layout_right::mapping: out of bounds indexing"); + TEST_LIBCPP_ASSERT_FAILURE(m(3, 3, 9), "layout_right::mapping: out of bounds indexing"); + TEST_LIBCPP_ASSERT_FAILURE(m(5, 7, 9), "layout_right::mapping: out of bounds indexing"); + } + { + std::layout_right::template mapping> m(std::dextents(5, 7, 9)); + TEST_LIBCPP_ASSERT_FAILURE(m(-1, -1, -1), "layout_right::mapping: out of bounds indexing"); + TEST_LIBCPP_ASSERT_FAILURE(m(-1, 0, 0), "layout_right::mapping: out of bounds indexing"); + TEST_LIBCPP_ASSERT_FAILURE(m(0, -1, 0), "layout_right::mapping: out of bounds indexing"); + TEST_LIBCPP_ASSERT_FAILURE(m(0, 0, -1), "layout_right::mapping: out of bounds indexing"); + TEST_LIBCPP_ASSERT_FAILURE(m(5, 3, 3), "layout_right::mapping: out of bounds indexing"); + TEST_LIBCPP_ASSERT_FAILURE(m(3, 7, 3), "layout_right::mapping: out of bounds indexing"); + TEST_LIBCPP_ASSERT_FAILURE(m(3, 3, 9), "layout_right::mapping: out of bounds indexing"); + TEST_LIBCPP_ASSERT_FAILURE(m(5, 7, 9), "layout_right::mapping: out of bounds indexing"); + } + return 0; +} Index: libcxx/test/std/containers/views/mdspan/layout_right/assert.stride.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/containers/views/mdspan/layout_right/assert.stride.pass.cpp @@ -0,0 +1,39 @@ +// +// 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 +// XFAIL: availability-verbose_abort-missing +// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1 + +// + +// layout_right::mapping +// +// 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 "check_assertion.h" + +int main(int, char**) { + // value out of range + { + std::layout_right::template mapping> m{std::dextents{100, 100, 100}}; + + TEST_LIBCPP_ASSERT_FAILURE(m.stride(4), "invalid rank index"); + } + return 0; +} Index: libcxx/test/std/containers/views/mdspan/layout_right/comparison.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/containers/views/mdspan/layout_right/comparison.pass.cpp @@ -0,0 +1,113 @@ +//===----------------------------------------------------------------------===// +// +// 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 mapping& y) noexcept; +// ` +// Constraints: extents_type::rank() == OtherExtents::rank() is true. + +#include +#include +#include +#include + +#include "test_macros.h" + +template +constexpr void test_comparison(bool equal, To dest_exts, From src_exts) { + std::layout_right::mapping dest(dest_exts); + std::layout_right::mapping src(src_exts); + 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, E2 e2) + -> decltype(std::layout_right::mapping(e1) == std::layout_right::mapping(e2)) { + return true; +} + +template +constexpr void test_comparison_different_rank() { + constexpr size_t D = std::dynamic_extent; + + // sanity check same rank + static_assert(compare_layout_mappings(std::extents(5), std::extents(5))); + static_assert(compare_layout_mappings(std::extents(), std::extents(5))); + static_assert(compare_layout_mappings(std::extents(5), std::extents())); + static_assert(compare_layout_mappings(std::extents(), std::extents())); + + // not equality comparable when rank is not the same + static_assert(compare_layout_mappings(std::extents(), std::extents(1)).does_not_match()); + static_assert(compare_layout_mappings(std::extents(), std::extents()).does_not_match()); + + static_assert(compare_layout_mappings(std::extents(1), std::extents()).does_not_match()); + static_assert(compare_layout_mappings(std::extents(), std::extents()).does_not_match()); + + static_assert(compare_layout_mappings(std::extents(5), std::extents(5, 5)).does_not_match()); + static_assert(compare_layout_mappings(std::extents(), std::extents(5)).does_not_match()); + static_assert(compare_layout_mappings(std::extents(), std::extents()).does_not_match()); + + static_assert(compare_layout_mappings(std::extents(5, 5), std::extents(5)).does_not_match()); + static_assert(compare_layout_mappings(std::extents(5), std::extents(5)).does_not_match()); + static_assert(compare_layout_mappings(std::extents(), std::extents()).does_not_match()); +} + +template +constexpr void test_comparison_same_rank() { + constexpr size_t D = std::dynamic_extent; + + test_comparison(true, std::extents(), std::extents()); + + test_comparison(true, std::extents(5), std::extents(5)); + test_comparison(true, std::extents(), std::extents(5)); + test_comparison(true, std::extents(5), std::extents()); + test_comparison(true, std::extents(), std::extents< T2, 5>()); + test_comparison(false, std::extents(5), std::extents(7)); + test_comparison(false, std::extents(), std::extents(7)); + test_comparison(false, std::extents(5), std::extents()); + test_comparison(false, std::extents(), std::extents()); + + test_comparison(true, std::extents(5, 6, 7, 8, 9), std::extents(5, 6, 7, 8, 9)); + test_comparison(true, std::extents(5, 7, 9), std::extents(6, 7)); + test_comparison(true, std::extents(5, 6, 7, 8, 9), std::extents()); + test_comparison( + false, std::extents(5, 6, 7, 8, 9), std::extents(5, 6, 3, 8, 9)); + test_comparison(false, std::extents(5, 7, 9), std::extents(6, 7)); + test_comparison(false, std::extents(5, 6, 7, 8, 9), std::extents()); +} + +template +constexpr void test_comparison() { + test_comparison_same_rank(); + test_comparison_different_rank(); +} + +constexpr bool test() { + test_comparison(); + test_comparison(); + test_comparison(); + test_comparison(); + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + return 0; +} Index: libcxx/test/std/containers/views/mdspan/layout_right/ctor.default.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/containers/views/mdspan/layout_right/ctor.default.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 + +// + +// Test default construction: +// +// constexpr mapping() noexcept = default; + +#include +#include +#include + +#include "test_macros.h" + +template +constexpr void test_construction() { + using M = std::layout_right::mapping; + ASSERT_NOEXCEPT(M{}); + M m; + E e; + + // check correct extents are returned + ASSERT_NOEXCEPT(m.extents()); + assert(m.extents() == e); + + // NOTE should we be passing it in instead + // 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_NOEXCEPT(m.required_span_size()); + assert(m.required_span_size() == expected_size); +} + +constexpr bool test() { + constexpr size_t D = std::dynamic_extent; + 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_right/ctor.extents.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/containers/views/mdspan/layout_right/ctor.extents.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 mapping(const extents_type&) noexcept; +// +// Preconditions: The size of the multidimensional index space e is representable +// as a value of type index_type ([basic.fundamental]). +// +// Effects: Direct-non-list-initializes extents_ with e. + +#include +#include +#include + +#include "test_macros.h" + +template +constexpr void test_construction(E e) { + using M = std::layout_right::mapping; + ASSERT_NOEXCEPT(M{e}); + M m(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_NOEXCEPT(m.required_span_size()); + assert(m.required_span_size() == expected_size); +} + +constexpr bool test() { + constexpr size_t D = std::dynamic_extent; + test_construction(std::extents()); + test_construction(std::extents(7)); + test_construction(std::extents()); + test_construction(std::extents()); + test_construction(std::extents(7, 9, 10)); + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + return 0; +} Index: libcxx/test/std/containers/views/mdspan/layout_right/ctor.layout_left.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/containers/views/mdspan/layout_right/ctor.layout_left.pass.cpp @@ -0,0 +1,127 @@ +//===----------------------------------------------------------------------===// +// +// 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(!is_convertible_v) +// mapping(const layout_left::mapping&) noexcept; + +// Constraints: +// - extents_type::rank() <= 1 is true, and +// - is_constructible_v is true. +// +// Preconditions: other.required_span_size() is representable as a value of type index_type + +#include +#include +#include // what do we use from there? +#include +#include + +#include "test_macros.h" + +template +constexpr void test_implicit_conversion(To dest, From src) { + assert(dest.extents() == src.extents()); +} + +template +constexpr void test_conversion(FromE src_exts) { + using To = std::layout_right::mapping; + using From = std::layout_left::mapping; + From src(src_exts); + + ASSERT_NOEXCEPT(To(src)); + To dest(src); + + assert(dest.extents() == src.extents()); + if constexpr (implicit) { + dest = src; + assert(dest.extents() == src.extents()); + test_implicit_conversion(src, src); + } +} + +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()); + + // clang-format off + test_conversion>(std::extents()); + test_conversion>(std::extents(5)); + test_conversion>(std::extents(5)); + test_conversion>(std::extents()); + // clang-format on +} + +template +using lr_mapping_t = typename std::layout_right::template mapping>; +template +using ll_mapping_t = typename std::layout_left::template mapping>; + +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, ll_mapping_t>); + static_assert(std::is_convertible_v, lr_mapping_t>); + + // Check that dynamic to static conversion only works explicitly + static_assert(std::is_constructible_v, ll_mapping_t>); + static_assert(!std::is_convertible_v, lr_mapping_t>); + + // Sanity check that smaller index_type to larger index_type conversion works + static_assert(std::is_constructible_v, ll_mapping_t>); + static_assert(std::is_convertible_v, lr_mapping_t>); + + // Check that larger index_type to smaller index_type conversion works explicitly only + static_assert(std::is_constructible_v, ll_mapping_t>); + static_assert(!std::is_convertible_v, lr_mapping_t>); +} + +constexpr void test_rank_mismatch() { + constexpr size_t D = std::dynamic_extent; + + static_assert(!std::is_constructible_v, ll_mapping_t>); + static_assert(!std::is_constructible_v, ll_mapping_t>); + static_assert(!std::is_constructible_v, ll_mapping_t>); + static_assert(!std::is_constructible_v, ll_mapping_t>); +} + +constexpr void test_static_extent_mismatch() { + static_assert(!std::is_constructible_v, ll_mapping_t>); +} + +constexpr void test_rank_greater_one() { + constexpr size_t D = std::dynamic_extent; + + static_assert(!std::is_constructible_v, ll_mapping_t>); + static_assert(!std::is_constructible_v, ll_mapping_t>); +} + +constexpr bool test() { + test_conversion(); + test_conversion(); + test_conversion(); + test_conversion(); + test_no_implicit_conversion(); + test_rank_mismatch(); + test_static_extent_mismatch(); + test_rank_greater_one(); + return true; +} + +int main(int, char**) { + test(); + //static_assert(test()); + return 0; +} Index: libcxx/test/std/containers/views/mdspan/layout_right/ctor.mapping.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/containers/views/mdspan/layout_right/ctor.mapping.pass.cpp @@ -0,0 +1,136 @@ +//===----------------------------------------------------------------------===// +// +// 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(!is_convertible_v) +// mapping(const mapping&) noexcept; + +// Constraints: is_constructible_v is true. +// +// Preconditions: other.required_span_size() is representable as a value of type index_type + +#include +#include +#include // what do we use from there? +#include +#include + +#include "test_macros.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_right::mapping; + using From = std::layout_right::mapping; + From src(src_exts); + + ASSERT_NOEXCEPT(To(src)); + To dest(src); + + assert(dest == src); + if constexpr (implicit) { + dest = src; + assert(dest == src); + test_implicit_conversion(src, src); + } +} + +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()); + + // clang-format off + 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 mapping_t = typename std::layout_right::template mapping>; + +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, mapping_t>); + static_assert(std::is_convertible_v, mapping_t>); + + // Check that dynamic to static conversion only works explicitly + static_assert(std::is_constructible_v, mapping_t>); + static_assert(!std::is_convertible_v, mapping_t>); + + // Sanity check that one static to dynamic conversion works + static_assert(std::is_constructible_v, mapping_t>); + static_assert(std::is_convertible_v, mapping_t>); + + // Check that dynamic to static conversion only works explicitly + static_assert(std::is_constructible_v, mapping_t>); + static_assert(!std::is_convertible_v, mapping_t>); + + // Sanity check that smaller index_type to larger index_type conversion works + static_assert(std::is_constructible_v, mapping_t>); + static_assert(std::is_convertible_v, mapping_t>); + + // Check that larger index_type to smaller index_type conversion works explicitly only + static_assert(std::is_constructible_v, mapping_t>); + static_assert(!std::is_convertible_v, mapping_t>); +} + +constexpr void test_rank_mismatch() { + constexpr size_t D = std::dynamic_extent; + + static_assert(!std::is_constructible_v, mapping_t>); + static_assert(!std::is_constructible_v, mapping_t>); + static_assert(!std::is_constructible_v, mapping_t>); + static_assert(!std::is_constructible_v, mapping_t>); +} + +constexpr void test_static_extent_mismatch() { + constexpr size_t D = std::dynamic_extent; + + static_assert(!std::is_constructible_v, mapping_t>); + static_assert(!std::is_constructible_v, mapping_t>); + static_assert(!std::is_constructible_v, mapping_t>); +} + +constexpr bool test() { + test_conversion(); + test_conversion(); + test_conversion(); + test_conversion(); + test_no_implicit_conversion(); + test_rank_mismatch(); + test_static_extent_mismatch(); + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + return 0; +} Index: libcxx/test/std/containers/views/mdspan/layout_right/extents.verify.cpp =================================================================== --- /dev/null +++ libcxx/test/std/containers/views/mdspan/layout_right/extents.verify.cpp @@ -0,0 +1,32 @@ +// +// 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 + +// + +// template +// class layout_left::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_right::mapping template argument must be a specialization of extents}} + [[maybe_unused]] std::layout_right::mapping mapping; +} + +void representable() { + // expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}layout_right::mapping product of static extents must be representable as index_type.}} + [[maybe_unused]] std::layout_right::mapping> mapping; +} Index: libcxx/test/std/containers/views/mdspan/layout_right/index_operator.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/containers/views/mdspan/layout_right/index_operator.pass.cpp @@ -0,0 +1,110 @@ +//===----------------------------------------------------------------------===// +// +// 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" + +struct IntType { + int val; + constexpr IntType() = default; + constexpr IntType(int v) noexcept : val(v){}; + + constexpr bool operator==(const IntType& rhs) const { return val == rhs.val; } + constexpr operator int() const noexcept { return val; } + constexpr operator unsigned char() const { return val; } +}; + + +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_right(M m, T& count, Args... args) { + constexpr size_t r = sizeof...(Args); + if constexpr (M::extents_type::rank() == r) { + ASSERT_NOEXCEPT(m(args...)); + assert(count == m(args...)); + count++; + } else { + for (typename M::index_type i = 0; i < m.extents().extent(r); i++) { + iterate_right(m, count, args..., i); + } + } +} + +template +constexpr void test_iteration(Args... args) { + using M = std::layout_right::mapping; + M m(E(args...)); + + typename E::index_type count = 0; + iterate_right(m, count); +} + +constexpr bool test() { + constexpr size_t D = std::dynamic_extent; + test_iteration>(); + test_iteration>(7); + test_iteration>(); + test_iteration>(); + test_iteration>(7, 9, 10); + + // Check operator constraint for number of arguments + static_assert(check_operator_constraints(std::layout_right::mapping>(std::extents(1)), 0)); + static_assert(!check_operator_constraints(std::layout_right::mapping>(std::extents(1)), 0, 0)); + + // Check operator constraint for convertibility of arguments to index_type + static_assert(check_operator_constraints(std::layout_right::mapping>(std::extents(1)), IntType(0))); + static_assert(!check_operator_constraints(std::layout_right::mapping>(std::extents(1)), IntType(0))); + + // Check operator constraint for no-throw-constructibility of index_type from arguments + static_assert(!check_operator_constraints(std::layout_right::mapping>(std::extents(1)), IntType(0))); + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + return 0; +} Index: libcxx/test/std/containers/views/mdspan/layout_right/properties.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/containers/views/mdspan/layout_right/properties.pass.cpp @@ -0,0 +1,65 @@ +//===----------------------------------------------------------------------===// +// +// 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_right::mapping { +// +// ... +// 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 true; } +// +// static constexpr bool is_unique() noexcept { return true; } +// static constexpr bool is_exhaustive() noexcept { return true; } +// static constexpr bool is_strided() noexcept { return true; } +// ... +// }; +// } + +#include +#include +#include +#include + +#include "test_macros.h" + +template +constexpr void test_layout_mapping_right() { + using M = std::layout_right::template mapping; + assert(M::is_unique() == true); + assert(M::is_exhaustive() == true); + assert(M::is_strided() == true); + assert(M::is_always_unique() == true); + assert(M::is_always_exhaustive() == true); + 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()); +} + +constexpr bool test() { + constexpr size_t D = std::dynamic_extent; + test_layout_mapping_right>(); + test_layout_mapping_right>(); + test_layout_mapping_right>(); + test_layout_mapping_right>(); + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + return 0; +} Index: libcxx/test/std/containers/views/mdspan/layout_right/static_requirements.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/containers/views/mdspan/layout_right/static_requirements.pass.cpp @@ -0,0 +1,130 @@ +//===----------------------------------------------------------------------===// +// +// 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_right); + 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()(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_right() { + test_layout_mapping_requirements(); +} + +int main(int, char**) { + constexpr size_t D = std::dynamic_extent; + test_layout_mapping_right>(); + test_layout_mapping_right>(); + test_layout_mapping_right>(); + test_layout_mapping_right>(); + return 0; +} Index: libcxx/test/std/containers/views/mdspan/layout_right/stride.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/containers/views/mdspan/layout_right/stride.pass.cpp @@ -0,0 +1,50 @@ +//===----------------------------------------------------------------------===// +// +// 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_right::mapping; + M m(E(args...)); + + ASSERT_NOEXCEPT(m.stride(0)); + for (size_t r = 0; r < E::rank(); r++) + assert(strides[r] == m.stride(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; +}