Index: libcxx/include/CMakeLists.txt =================================================================== --- libcxx/include/CMakeLists.txt +++ libcxx/include/CMakeLists.txt @@ -480,6 +480,7 @@ __mdspan/extents.h __mdspan/layout_left.h __mdspan/layout_right.h + __mdspan/mdspan.h __memory/addressof.h __memory/align.h __memory/aligned_alloc.h Index: libcxx/include/__mdspan/mdspan.h =================================================================== --- /dev/null +++ libcxx/include/__mdspan/mdspan.h @@ -0,0 +1,309 @@ +// -*- 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_MDSPAN_H +#define _LIBCPP___MDSPAN_MDSPAN_H + +#include <__assert> +#include <__config> +#include <__fwd/mdspan.h> +#include <__mdspan/default_accessor.h> +#include <__mdspan/extents.h> +#include <__type_traits/extent.h> +#include <__type_traits/is_abstract.h> +#include <__type_traits/is_array.h> +#include <__type_traits/is_constructible.h> +#include <__type_traits/is_convertible.h> +#include <__type_traits/is_default_constructible.h> +#include <__type_traits/is_nothrow_constructible.h> +#include <__type_traits/is_pointer.h> +#include <__type_traits/is_same.h> +#include <__type_traits/rank.h> +#include <__type_traits/remove_all_extents.h> +#include <__type_traits/remove_cv.h> +#include <__type_traits/remove_pointer.h> +#include <__type_traits/remove_reference.h> +#include <__utility/as_const.h> +#include <__utility/integer_sequence.h> +#include +#include +#include +#include +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 23 + +// Helper for lightweight test checking that one didn't pass mapping instead of layout to mdspan +namespace __mdspan_detail { +template +_LIBCPP_HIDE_FROM_ABI constexpr bool __is_possibly_mapping() { + return false; +}; + +template + requires(is_same_v<_Mapping, typename _Mapping::layout_type::template mapping>) +_LIBCPP_HIDE_FROM_ABI constexpr bool __is_possibly_mapping() { + return true; +} +} // namespace __mdspan_detail + +template < class _ElementType, + class _Extents, + class _LayoutPolicy = layout_right, + class _AccessorPolicy = default_accessor<_ElementType> > +class mdspan { +private: + static_assert(__mdspan_detail::__is_extents_v<_Extents>, + "mdspan: Extents template parameter must be a specialization of extents."); + static_assert(!is_array_v<_ElementType>, "mdspan: ElementType template parameter may not be an array type"); + static_assert(!is_abstract_v<_ElementType>, "mdspan: ElementType template parameter may not be an abstract class"); + static_assert(is_same_v<_ElementType, typename _AccessorPolicy::element_type>, + "mdspan: ElementType template parameter must match AccessorPolicy::element_type"); + static_assert(!__mdspan_detail::__is_possibly_mapping<_LayoutPolicy>(), + "mdspan: likely passed layout mapping template parameter instead of layout policy"); + + // Workaround for non-deducibility of the index sequence template parameter if it's given at the top level + template + struct __deduction_workaround; + + template + struct __deduction_workaround> { + _LIBCPP_HIDE_FROM_ABI static constexpr size_t __size(mdspan const& __self) noexcept { + return ((__self.__map_.extents().extent(_Idxs)) * ... * size_t(1)); + } + _LIBCPP_HIDE_FROM_ABI static constexpr bool __empty(mdspan const& __self) noexcept { + return (__self.rank() > 0) && ((__self.__map_.extents().extent(_Idxs) == index_type(0)) || ... || false); + } + template + _LIBCPP_HIDE_FROM_ABI static constexpr _ReferenceType + __callop(mdspan const& __self, const array<_OtherIndexType, _Size>& __indices) noexcept { + return __self.__acc_.access(__self.__ptr_, __self.__map_(__indices[_Idxs]...)); + } + }; + +public: + //-------------------------------------------------------------------------------- + // Domain and codomain types + + using extents_type = _Extents; + using layout_type = _LayoutPolicy; + using accessor_type = _AccessorPolicy; + using mapping_type = typename layout_type::template mapping; + using element_type = _ElementType; + using value_type = remove_cv_t; + 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 data_handle_type = typename accessor_type::data_handle_type; + using reference = typename accessor_type::reference; + + _LIBCPP_HIDE_FROM_ABI static constexpr size_t rank() noexcept { return extents_type::rank(); } + _LIBCPP_HIDE_FROM_ABI static constexpr size_t rank_dynamic() noexcept { return extents_type::rank_dynamic(); } + _LIBCPP_HIDE_FROM_ABI static constexpr size_t static_extent(size_t __r) noexcept { + return extents_type::static_extent(__r); + } + _LIBCPP_HIDE_FROM_ABI constexpr index_type extent(size_t __r) const noexcept { return __map_.extents().extent(__r); }; + +private: + // Can't use defaulted parameter in the __deduction_workaround template because of a bug in MSVC warning C4348. + using __impl = __deduction_workaround>; + +public: + //-------------------------------------------------------------------------------- + // [mdspan.basic.cons], mdspan constructors, assignment, and destructor + + _LIBCPP_HIDE_FROM_ABI constexpr mdspan() + requires( + // nvhpc has a bug where using just rank_dynamic() here doesn't work ... + (extents_type::rank_dynamic() > 0) && is_default_constructible_v && + is_default_constructible_v && is_default_constructible_v) + = default; + _LIBCPP_HIDE_FROM_ABI constexpr mdspan(const mdspan&) = default; + _LIBCPP_HIDE_FROM_ABI constexpr mdspan(mdspan&&) = default; + + template + requires((is_convertible_v<_OtherIndexTypes, index_type> && ...) && + (is_nothrow_constructible_v && ...) && + ((sizeof...(_OtherIndexTypes) == rank()) || (sizeof...(_OtherIndexTypes) == rank_dynamic())) && + is_constructible_v && is_default_constructible_v) + _LIBCPP_HIDE_FROM_ABI explicit constexpr mdspan(data_handle_type __p, _OtherIndexTypes... __exts) + : __ptr_(std::move(__p)), __map_(extents_type(static_cast(std::move(__exts))...)), __acc_{} {} + + template + requires(is_convertible_v && + is_nothrow_constructible_v && + ((_Size == rank()) || (_Size == rank_dynamic())) && is_constructible_v && + is_default_constructible_v) + explicit(_Size != rank_dynamic()) + _LIBCPP_HIDE_FROM_ABI constexpr mdspan(data_handle_type __p, const array<_OtherIndexType, _Size>& __exts) + : __ptr_(std::move(__p)), __map_(extents_type(__exts)), __acc_{} {} + + template < class _OtherIndexType, size_t _Size> + requires(is_convertible_v<_OtherIndexType, index_type> && is_nothrow_constructible_v && + ((_Size == rank()) || (_Size == rank_dynamic())) && is_constructible_v && + is_default_constructible_v) + explicit(_Size != rank_dynamic()) + _LIBCPP_HIDE_FROM_ABI constexpr mdspan(data_handle_type __p, span<_OtherIndexType, _Size> __exts) + : __ptr_(std::move(__p)), __map_(extents_type(std::as_const(__exts))), __acc_{} {} + + _LIBCPP_HIDE_FROM_ABI constexpr mdspan(data_handle_type __p, const extents_type& __exts) + requires(is_default_constructible_v && is_constructible_v) + : __ptr_(std::move(__p)), __map_(__exts), __acc_{} {} + + _LIBCPP_HIDE_FROM_ABI constexpr mdspan(data_handle_type __p, const mapping_type& __m) + requires(is_default_constructible_v) + : __ptr_(std::move(__p)), __map_(__m), __acc_{} {} + + _LIBCPP_HIDE_FROM_ABI constexpr mdspan(data_handle_type __p, const mapping_type& __m, const accessor_type& __a) + : __ptr_(std::move(__p)), __map_(__m), __acc_(__a) {} + + template < class _OtherElementType, class _OtherExtents, class _OtherLayoutPolicy, class _OtherAccessor> + requires(is_constructible_v> && + is_constructible_v) + explicit(!is_convertible_v&, mapping_type> || + !is_convertible_v) + _LIBCPP_HIDE_FROM_ABI constexpr mdspan( + const mdspan<_OtherElementType, _OtherExtents, _OtherLayoutPolicy, _OtherAccessor>& __other) + : __ptr_(__other.__ptr_), __map_(__other.__map_), __acc_(__other.__acc_) { + static_assert(is_constructible_v, + "mdspan: incompatible data_handle_type for mdspan construction"); + static_assert( + is_constructible_v, "mdspan: incompatible extents for mdspan construction"); + /* + * TODO: Check precondition + * For each rank index r of extents_type, static_extent(r) == dynamic_extent || static_extent(r) == other.extent(r) + * is true. + */ + } + + _LIBCPP_HIDE_FROM_ABI constexpr mdspan& operator=(const mdspan&) = default; + _LIBCPP_HIDE_FROM_ABI constexpr mdspan& operator=(mdspan&&) = default; + + //-------------------------------------------------------------------------------- + // [mdspan.basic.mapping], mdspan mapping domain multidimensional index to access codomain element + + template < class... _OtherIndexTypes> + requires((is_convertible_v<_OtherIndexTypes, index_type> && ...) && + (is_nothrow_constructible_v && ...) && + (rank() == sizeof...(_OtherIndexTypes))) + _LIBCPP_HIDE_FROM_ABI constexpr reference operator[](_OtherIndexTypes... __indices) const { + return __acc_.access(__ptr_, __map_(static_cast(std::move(__indices))...)); + } + + template < class _OtherIndexType> + requires(is_convertible_v<_OtherIndexType, index_type> && is_nothrow_constructible_v) + _LIBCPP_HIDE_FROM_ABI constexpr reference operator[](const array< _OtherIndexType, rank()>& __indices) const { + return __impl::template __callop(*this, __indices); + } + + template < class _OtherIndexType> + requires(is_convertible_v<_OtherIndexType, index_type> && is_nothrow_constructible_v) + _LIBCPP_HIDE_FROM_ABI constexpr reference operator[](span<_OtherIndexType, rank()> __indices) const { + return __impl::template __callop(*this, __indices); + } + + _LIBCPP_HIDE_FROM_ABI constexpr size_type size() const noexcept { return __impl::__size(*this); } + + _LIBCPP_HIDE_FROM_ABI constexpr bool empty() const noexcept { return __impl::__empty(*this); } + + _LIBCPP_HIDE_FROM_ABI friend constexpr void swap(mdspan& __x, mdspan& __y) noexcept { + swap(__x.__ptr_, __y.__ptr_); + swap(__x.__map_, __y.__map_); + swap(__x.__acc_, __y.__acc_); + } + + //-------------------------------------------------------------------------------- + // [mdspan.basic.domobs], mdspan observers of the domain multidimensional index space + + _LIBCPP_HIDE_FROM_ABI constexpr const extents_type& extents() const noexcept { return __map_.extents(); }; + _LIBCPP_HIDE_FROM_ABI constexpr const data_handle_type& data_handle() const noexcept { return __ptr_; }; + _LIBCPP_HIDE_FROM_ABI constexpr const mapping_type& mapping() const noexcept { return __map_; }; + _LIBCPP_HIDE_FROM_ABI constexpr const accessor_type& accessor() const noexcept { return __acc_; }; + + //-------------------------------------------------------------------------------- + // [mdspan.basic.obs], mdspan observers of the mapping + + _LIBCPP_HIDE_FROM_ABI static constexpr bool is_always_unique() { return mapping_type::is_always_unique(); }; + _LIBCPP_HIDE_FROM_ABI static constexpr bool is_always_exhaustive() { return mapping_type::is_always_exhaustive(); }; + _LIBCPP_HIDE_FROM_ABI static constexpr bool is_always_strided() { return mapping_type::is_always_strided(); }; + + _LIBCPP_HIDE_FROM_ABI constexpr bool is_unique() const { return __map_.is_unique(); }; + _LIBCPP_HIDE_FROM_ABI constexpr bool is_exhaustive() const { return __map_.is_exhaustive(); }; + _LIBCPP_HIDE_FROM_ABI constexpr bool is_strided() const { return __map_.is_strided(); }; + _LIBCPP_HIDE_FROM_ABI constexpr index_type stride(size_t __r) const { return __map_.stride(__r); }; + +private: + _LIBCPP_NO_UNIQUE_ADDRESS data_handle_type __ptr_{}; + _LIBCPP_NO_UNIQUE_ADDRESS mapping_type __map_{}; + _LIBCPP_NO_UNIQUE_ADDRESS accessor_type __acc_{}; + + template + friend class mdspan; +}; + +template < class _ElementType, class... _OtherIndexTypes> + requires((is_convertible_v<_OtherIndexTypes, size_t> && ...) && (sizeof...(_OtherIndexTypes) > 0)) +explicit mdspan(_ElementType*, _OtherIndexTypes...) + -> mdspan<_ElementType, dextents>; + +template < class Pointer> + requires(is_pointer_v>) +mdspan(Pointer&&) -> mdspan>, extents>; + +template < class CArray> + requires(is_array_v && (rank_v == 1)) +mdspan(CArray&) -> mdspan, extents>>; + +template +mdspan(_ElementType*, const array<_OtherIndexType, _Size>&) -> mdspan<_ElementType, dextents>; + +template +mdspan(_ElementType*, span<_OtherIndexType, _Size>) -> mdspan<_ElementType, dextents>; + +// This one is necessary because all the constructors take `data_handle_type`s, not +// `_ElementType*`s, and `data_handle_type` is taken from `accessor_type::data_handle_type`, which +// seems to throw off automatic deduction guides. +template +mdspan(_ElementType*, const extents<_OtherIndexType, _ExtentsPack...>&) + -> mdspan<_ElementType, extents<_OtherIndexType, _ExtentsPack...>>; + +template +mdspan(_ElementType*, const MappingType&) + -> mdspan<_ElementType, typename MappingType::extents_type, typename MappingType::layout_type>; + +template +mdspan(const typename AccessorType::data_handle_type, const MappingType&, const AccessorType&) + -> mdspan; + +#endif // _LIBCPP_STD_VER >= 23 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___MDSPAN_MDSPAN_H Index: libcxx/include/mdspan =================================================================== --- libcxx/include/mdspan +++ libcxx/include/mdspan @@ -208,6 +208,135 @@ }; } +// mdspan synopsis + +namespace std { + template> + class mdspan { + public: + using extents_type = Extents; + using layout_type = LayoutPolicy; + using accessor_type = AccessorPolicy; + using mapping_type = typename layout_type::template mapping; + using element_type = ElementType; + using value_type = remove_cv_t; + 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 data_handle_type = typename accessor_type::data_handle_type; + using reference = typename accessor_type::reference; + + static constexpr rank_type rank() noexcept { return extents_type::rank(); } + static constexpr rank_type rank_dynamic() noexcept { return extents_type::rank_dynamic(); } + static constexpr size_t static_extent(rank_type r) noexcept + { return extents_type::static_extent(r); } + constexpr index_type extent(rank_type r) const noexcept { return extents().extent(r); } + + // [mdspan.mdspan.cons], constructors + constexpr mdspan(); + constexpr mdspan(const mdspan& rhs) = default; + constexpr mdspan(mdspan&& rhs) = default; + + template + constexpr explicit mdspan(data_handle_type ptr, OtherIndexTypes... exts); + template + constexpr explicit(N != rank_dynamic()) + mdspan(data_handle_type p, span exts); + template + constexpr explicit(N != rank_dynamic()) + mdspan(data_handle_type p, const array& exts); + constexpr mdspan(data_handle_type p, const extents_type& ext); + constexpr mdspan(data_handle_type p, const mapping_type& m); + constexpr mdspan(data_handle_type p, const mapping_type& m, const accessor_type& a); + + template + constexpr explicit(see below) + mdspan(const mdspan& other); + + constexpr mdspan& operator=(const mdspan& rhs) = default; + constexpr mdspan& operator=(mdspan&& rhs) = default; + + // [mdspan.mdspan.members], members + template + constexpr reference operator[](OtherIndexTypes... indices) const; + template + constexpr reference operator[](span indices) const; + template + constexpr reference operator[](const array& indices) const; + + constexpr size_type size() const noexcept; + [[nodiscard]] constexpr bool empty() const noexcept; + + friend constexpr void swap(mdspan& x, mdspan& y) noexcept; + + constexpr const extents_type& extents() const noexcept { return map_.extents(); } + constexpr const data_handle_type& data_handle() const noexcept { return ptr_; } + constexpr const mapping_type& mapping() const noexcept { return map_; } + constexpr const accessor_type& accessor() const noexcept { return acc_; } + + static constexpr bool is_always_unique() + { return mapping_type::is_always_unique(); } + static constexpr bool is_always_exhaustive() + { return mapping_type::is_always_exhaustive(); } + static constexpr bool is_always_strided() + { return mapping_type::is_always_strided(); } + + constexpr bool is_unique() const + { return map_.is_unique(); } + constexpr bool is_exhaustive() const + { return map_.is_exhaustive(); } + constexpr bool is_strided() const + { return map_.is_strided(); } + constexpr index_type stride(rank_type r) const + { return map_.stride(r); } + + private: + accessor_type acc_; // exposition only + mapping_type map_; // exposition only + data_handle_type ptr_; // exposition only + }; + + template + requires(is_array_v && rank_v == 1) + mdspan(CArray&) + -> mdspan, extents>>; + + template + requires(is_pointer_v>) + mdspan(Pointer&&) + -> mdspan>, extents>; + + template + requires((is_convertible_v && ...) && sizeof...(Integrals) > 0) + explicit mdspan(ElementType*, Integrals...) + -> mdspan>; + + template + mdspan(ElementType*, span) + -> mdspan>; + + template + mdspan(ElementType*, const array&) + -> mdspan>; + + template + mdspan(ElementType*, const extents&) + -> mdspan>; + + template + mdspan(ElementType*, const MappingType&) + -> mdspan; + + template + mdspan(const typename AccessorType::data_handle_type&, const MappingType&, + const AccessorType&) + -> mdspan; +} */ #ifndef _LIBCPP_MDSPAN @@ -219,6 +348,7 @@ #include <__mdspan/extents.h> #include <__mdspan/layout_left.h> #include <__mdspan/layout_right.h> +#include <__mdspan/mdspan.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 @@ -1176,6 +1176,7 @@ } module layout_left { private header "__mdspan/layout_left.h" } module layout_right { private header "__mdspan/layout_right.h" } + module mdspan { private header "__mdspan/mdspan.h" } module mdspan_fwd { private header "__fwd/mdspan.h" } } } Index: libcxx/modules/std/mdspan.cppm =================================================================== --- libcxx/modules/std/mdspan.cppm +++ libcxx/modules/std/mdspan.cppm @@ -27,5 +27,5 @@ using std::default_accessor; // [mdspan.mdspan], class template mdspan - // using std::mdspan; + using std::mdspan; } // namespace std Index: libcxx/test/std/containers/views/mdspan/mdspan/CustomTestAccessors.h =================================================================== --- /dev/null +++ libcxx/test/std/containers/views/mdspan/mdspan/CustomTestAccessors.h @@ -0,0 +1,105 @@ +// -*- 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 TEST_STD_CONTAINERS_VIEWS_MDSPAN_MDSPAN_CUSTOM_TEST_ACCESSORS_H +#define TEST_STD_CONTAINERS_VIEWS_MDSPAN_MDSPAN_CUSTOM_TEST_ACCESSORS_H + +#include +#include + +// non default constructible data handle +template +struct no_default_ctor_handle { + T* ptr; + no_default_ctor_handle() = delete; + constexpr no_default_ctor_handle(T* ptr_) : ptr(ptr_) {} +}; + +// non-default constructible accessor +// when instantiated with double, also use non-default constructible, not T* data_handle +template +struct checked_accessor { + size_t N; + using offset_policy = std::default_accessor<_ElementType>; + using element_type = _ElementType; + using reference = _ElementType&; + using data_handle_type = _ElementType*; + + constexpr checked_accessor(size_t N_) : N(N_) {} + template + requires(std::is_convertible_v<_OtherElementType (*)[], element_type (*)[]>) + explicit _LIBCPP_HIDE_FROM_ABI constexpr checked_accessor(const checked_accessor<_OtherElementType>& other) noexcept { + N = other.N; + } + + _LIBCPP_HIDE_FROM_ABI constexpr reference access(data_handle_type __p, size_t __i) const noexcept { + assert(__i < N); + return __p[__i]; + } + _LIBCPP_HIDE_FROM_ABI constexpr data_handle_type offset(data_handle_type __p, size_t __i) const noexcept { + assert(__i < N); + return __p + __i; + } +}; + +template <> +struct checked_accessor { + size_t N; + using offset_policy = std::default_accessor; + using element_type = double; + using reference = double&; + using data_handle_type = no_default_ctor_handle; + + constexpr checked_accessor(size_t N_) : N(N_) {} + template + requires(std::is_convertible_v<_OtherElementType (*)[], element_type (*)[]>) + _LIBCPP_HIDE_FROM_ABI constexpr checked_accessor(const checked_accessor<_OtherElementType>& other) noexcept { + N = other.N; + } + + _LIBCPP_HIDE_FROM_ABI constexpr reference access(data_handle_type __p, size_t __i) const noexcept { + assert(__i < N); + return __p.ptr[__i]; + } + _LIBCPP_HIDE_FROM_ABI constexpr data_handle_type offset(data_handle_type __p, size_t __i) const noexcept { + assert(__i < N); + return __p.ptr + __i; + } +}; + +template <> +struct checked_accessor { + size_t N; + using offset_policy = std::default_accessor; + using element_type = const double; + using reference = const double&; + using data_handle_type = const double*; + + constexpr checked_accessor() : N(0) {} + constexpr checked_accessor(size_t N_) : N(N_) {} + constexpr checked_accessor(const checked_accessor& acc) : N(acc.N) {} + + _LIBCPP_HIDE_FROM_ABI constexpr reference access(data_handle_type __p, size_t __i) const noexcept { + assert(__i < N); + return __p[__i]; + } + _LIBCPP_HIDE_FROM_ABI constexpr data_handle_type offset(data_handle_type __p, size_t __i) const noexcept { + assert(__i < N); + return __p + __i; + } +}; + +#endif // TEST_STD_CONTAINERS_VIEWS_MDSPAN_MDSPAN_CUSTOM_TEST_ACCESSORS_H Index: libcxx/test/std/containers/views/mdspan/mdspan/CustomTestLayouts.h =================================================================== --- /dev/null +++ libcxx/test/std/containers/views/mdspan/mdspan/CustomTestLayouts.h @@ -0,0 +1,186 @@ +// -*- 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 TEST_STD_CONTAINERS_VIEWS_MDSPAN_MDSPAN_CUSTOM_TEST_LAYOUTS_H +#define TEST_STD_CONTAINERS_VIEWS_MDSPAN_MDSPAN_CUSTOM_TEST_LAYOUTS_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Layout that wraps indices to test some idiosyncratic behavior +// - only accepts integers as indices +// - is_always_strided and is_always_unique are false +// - is_strided and is_unique are true if all extents are smaller than _Wrap +// - not default constructible +// - not extents constructible + +struct not_extents_constructible_tag {}; + +template +class layout_wrapping_integral { +public: + template + class mapping; +}; + +template +template +class layout_wrapping_integral<_WrapArg>::mapping { + static constexpr _Extents::index_type _Wrap = static_cast<_Extents::index_type>(_WrapArg); + +public: + static_assert(std::__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_wrapping_integral<_Wrap>; + +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.left.cons], constructors + _LIBCPP_HIDE_FROM_ABI constexpr mapping() noexcept = delete; + _LIBCPP_HIDE_FROM_ABI constexpr mapping(const mapping&) noexcept = default; + _LIBCPP_HIDE_FROM_ABI constexpr mapping(const extents_type& __ext, not_extents_constructible_tag) 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(std::is_constructible_v) + _LIBCPP_HIDE_FROM_ABI constexpr explicit(!std::is_convertible_v<_OtherExtents, extents_type>) + mapping(const mapping<_OtherExtents>& __other) noexcept + : __extents_(__other.extents()) { + _LIBCPP_ASSERT( + std::__mdspan_detail::__is_representable_as(__other.required_span_size()), + "layout_left::mapping converting ctor: other.required_span_size() must be representable as index_type."); + } + + _LIBCPP_HIDE_FROM_ABI constexpr mapping& operator=(const mapping&) noexcept = default; + + // [mdspan.layout.left.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) < _Wrap ? __extents_.extent(__r) : _Wrap; + return __size; + } + + template + requires((sizeof...(_Indices) == extents_type::rank()) && (std::is_convertible_v<_Indices, index_type> && ...) && + (std::is_nothrow_constructible_v && ...)) + _LIBCPP_HIDE_FROM_ABI constexpr index_type operator()(_Indices... __idx) const noexcept { + _LIBCPP_ASSERT(std::__mdspan_detail::__is_multidimensional_index_in(__extents_, __idx...), + "layout_left::mapping: out of bounds indexing"); + std::array __idx_a{ + static_cast(static_cast(__idx) % _Wrap)...}; + return [&](std::index_sequence<_Pos...>) { + index_type __res = 0; + ((__res = __idx_a[extents_type::rank() - 1 - _Pos] + + (__extents_.extent(extents_type::rank() - 1 - _Pos) < _Wrap + ? __extents_.extent(extents_type::rank() - 1 - _Pos) + : _Wrap) * + __res), + ...); + return __res; + }(std::make_index_sequence()); + } + + _LIBCPP_HIDE_FROM_ABI static constexpr bool is_always_unique() noexcept { return false; } + _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 false; } + + _LIBCPP_HIDE_FROM_ABI constexpr bool is_unique() const noexcept { + for (rank_type r = 0; r < extents_type::rank(); r++) { + if (__extents_.extent(r) > _Wrap) + return false; + } + return true; + } + _LIBCPP_HIDE_FROM_ABI static constexpr bool is_exhaustive() noexcept { return true; } + _LIBCPP_HIDE_FROM_ABI constexpr bool is_strided() const noexcept { + for (rank_type r = 0; r < extents_type::rank(); r++) { + if (__extents_.extent(r) > _Wrap) + return false; + } + 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 +}; + +template +constexpr auto construct_mapping(std::layout_left, Extents exts) { + return std::layout_left::mapping(exts); +} + +template +constexpr auto construct_mapping(std::layout_right, Extents exts) { + return std::layout_right::mapping(exts); +} + +template +constexpr auto construct_mapping(layout_wrapping_integral<_Wraps>, Extents exts) { + return typename layout_wrapping_integral<_Wraps>::template mapping(exts, not_extents_constructible_tag{}); +} + +#endif // TEST_STD_CONTAINERS_VIEWS_MDSPAN_MDSPAN_CUSTOM_TEST_LAYOUTS_H Index: libcxx/test/std/containers/views/mdspan/mdspan/conversion.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/containers/views/mdspan/mdspan/conversion.pass.cpp @@ -0,0 +1,249 @@ +//===----------------------------------------------------------------------===// +// +// 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 mdspan(data_handle_type p, const mapping_type& m, const accessor_type& a); +// +// Preconditions: [0, m.required_span_size()) is an accessible range of p and a. +// +// Effects: +// - Direct-non-list-initializes ptr_ with std::move(p), +// - direct-non-list-initializes map_ with m, and +// - direct-non-list-initializes acc_ with a. + +#include +#include +#include +#include + +#include "test_macros.h" + +#include "../MinimalElementType.h" +#include "CustomTestLayouts.h" +#include "CustomTestAccessors.h" + +// some weird things we rely on in cornercases: +// - pointer of element types would be convertible but accessors of those are not +static_assert(!std::is_constructible_v, checked_accessor>); +// - dynamic to static is not convertible +static_assert(!std::is_convertible_v, std::extents>); +// - checked_accessor is idiosyncratic: its never convertible between different types +static_assert(std::is_constructible_v, checked_accessor>); +static_assert(!std::is_convertible_v, checked_accessor>); +// - checked_accessor is idiosyncratic: its not constructible from const to non-const for double +static_assert(!std::is_constructible_v, checked_accessor>); +static_assert(!std::is_convertible_v, checked_accessor>); + +template +constexpr void test_implicit_conversion(ToMDS to_mds, FromMDS from_mds) { + assert(to_mds.extents() == from_mds.extents()); + if constexpr (std::equality_comparable_with) + assert(to_mds.data_handle() == from_mds.data_handle()); + if constexpr (std::equality_comparable_with) + assert(to_mds.mapping() == from_mds.mapping()); + if constexpr (std::equality_comparable_with) + assert(to_mds.accessor() == from_mds.accessor()); +} + +template +constexpr void test_conversion(FromMDS from_mds) { + using ToMDS = std::mdspan; + + if constexpr (constructible) { + ToMDS to_mds(from_mds); + assert(to_mds.extents() == from_mds.extents()); + if constexpr (std::equality_comparable_with) + assert(to_mds.data_handle() == from_mds.data_handle()); + if constexpr (std::equality_comparable_with) + assert(to_mds.mapping() == from_mds.mapping()); + if constexpr (std::equality_comparable_with) + assert(to_mds.accessor() == from_mds.accessor()); + if constexpr (convertible) { + test_implicit_conversion(from_mds, from_mds); + } else { + static_assert(!std::is_convertible_v); + } + } else { + static_assert(!std::is_constructible_v); + } +} + +template +constexpr void mixin_tomds_extents(FromMDS m) { + using FromMapping = typename FromMDS::mapping_type; + constexpr size_t D = std::dynamic_extent; + { + using ToMapping = decltype(construct_mapping(L(), std::extents())); + test_conversion, + convertible && std::is_convertible_v, + ToMapping, ToA>(m); + } + { + using ToMapping = decltype(construct_mapping(L(), std::extents())); + test_conversion, + convertible && std::is_convertible_v, + ToMapping, ToA>(m); + } + { + using ToMapping = decltype(construct_mapping(L(), std::extents(3))); + test_conversion, + convertible && std::is_convertible_v, + ToMapping, ToA>(m); + } + { + using ToMapping = decltype(construct_mapping(L(), std::extents())); + test_conversion, + convertible && std::is_convertible_v, + ToMapping, ToA>(m); + } + { + using ToMapping = decltype(construct_mapping(L(), std::extents(3))); + test_conversion, + convertible && std::is_convertible_v, + ToMapping, ToA>(m); + } + { + using ToMapping = decltype(construct_mapping(L(), std::extents())); + test_conversion, + convertible && std::is_convertible_v, + ToMapping, ToA>(m); + } + { + using ToMapping = decltype(construct_mapping(L(), std::extents(3))); + test_conversion, + convertible && std::is_convertible_v, + ToMapping, ToA>(m); + } + { + using ToMapping = decltype(construct_mapping(L(), std::extents(3, 5))); + test_conversion, + convertible && std::is_convertible_v, + ToMapping, ToA>(m); + } + { + using ToMapping = decltype(construct_mapping(L(), std::extents(3, 5))); + test_conversion, + convertible && std::is_convertible_v, + ToMapping, ToA>(m); + } + { + using ToMapping = decltype(construct_mapping(L(), std::extents(5))); + test_conversion, + convertible && std::is_convertible_v, + ToMapping, ToA>(m); + } +} + +// defer more info on constructible/convertible until we got the mapping +template +constexpr void mixin_tomds_layout(FromMDS m) { + mixin_tomds_extents(m); + mixin_tomds_extents(m); + mixin_tomds_extents, ToA>(m); +} + +template +constexpr void mixin_tomds_accessor(FromMDS m) { + using FromA = typename FromMDS::accessor_type; + mixin_tomds_layout, const FromA&>, + std::is_convertible_v>, + std::default_accessor>(m); + + // Using weird accessor/data_handle + // Make sure they actually got the properties we want to test + // checked_accessor is not default constructible except for const double, where it is not noexcept + static_assert(std::is_default_constructible_v> == std::is_same_v); + // checked_accessor's data handle type is not default constructible for double + static_assert( + std::is_default_constructible_v::data_handle_type> != std::is_same_v); + mixin_tomds_layout, const FromA&>, + std::is_convertible_v>, + checked_accessor>(m); +} + +template +constexpr void mixin_tomds_element_type(FromMDS m) { + using T = typename FromMDS::element_type; + { + constexpr bool constructible = std::is_same_v; + mixin_tomds_accessor(m); + } + { + constexpr bool constructible = std::is_same_v || std::is_same_v; + mixin_tomds_accessor(m); + } + { + constexpr bool constructible = std::is_same_v; + mixin_tomds_accessor(m); + } + { + constexpr bool constructible = std::is_same_v || std::is_same_v; + mixin_tomds_accessor(m); + } + { + constexpr bool constructible = std::is_same_v; + mixin_tomds_accessor(m); + } + { + constexpr bool constructible = std::is_same_v || std::is_same_v; + mixin_tomds_accessor(m); + } +} + +template +constexpr void mixin_extents(const H& handle, const L& layout, const A& acc) { + constexpr size_t D = std::dynamic_extent; + mixin_tomds_element_type(std::mdspan(handle, construct_mapping(layout, std::extents()), acc)); + mixin_tomds_element_type(std::mdspan(handle, construct_mapping(layout, std::extents(3)), acc)); + mixin_tomds_element_type(std::mdspan(handle, construct_mapping(layout, std::extents()), acc)); + mixin_tomds_element_type(std::mdspan(handle, construct_mapping(layout, std::extents(3, 5)), acc)); + mixin_tomds_element_type(std::mdspan(handle, construct_mapping(layout, std::extents(3, 5)), acc)); +} + +template +constexpr void mixin_layout(const H& handle, const A& acc) { + mixin_extents(handle, std::layout_left(), acc); + mixin_extents(handle, std::layout_right(), acc); + mixin_extents(handle, layout_wrapping_integral<4>(), acc); +} + +template +constexpr void mixin_accessor() { + ElementPool elements; + mixin_layout(elements.get_ptr(), std::default_accessor()); + mixin_layout(typename checked_accessor::data_handle_type(elements.get_ptr()), checked_accessor(1024)); +} + +constexpr bool test() { + mixin_accessor(); + mixin_accessor(); + mixin_accessor(); + mixin_accessor(); + mixin_accessor(); + mixin_accessor(); + return true; +} +int main(int, char**) { + (void)test(); + static_assert(test()); + return 0; +} Index: libcxx/test/std/containers/views/mdspan/mdspan/ctor.copy.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/containers/views/mdspan/mdspan/ctor.copy.pass.cpp @@ -0,0 +1,85 @@ +//===----------------------------------------------------------------------===// +// +// 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 mdspan(const mdspan&) = default; + +#include +#include +#include +#include + +#include "test_macros.h" + +#include "../MinimalElementType.h" +#include "CustomTestLayouts.h" +#include "CustomTestAccessors.h" + +template +constexpr void test_mdspan_types(const H& handle, const M& map, const A& acc) { + using MDS = std::mdspan; + + MDS m_org(handle, map, acc); + MDS m(m_org); + static_assert(noexcept(MDS(m_org)) == (noexcept(H(handle))&& noexcept(M(map))&& noexcept(A(acc)))); + assert(m.extents() == map.extents()); + if constexpr (std::equality_comparable) + assert(m.data_handle() == handle); + if constexpr (std::equality_comparable) + assert(m.mapping() == map); + if constexpr (std::equality_comparable) + assert(m.accessor() == acc); +} + +template +constexpr void mixin_extents(const H& handle, const L& layout, const A& acc) { + constexpr size_t D = std::dynamic_extent; + test_mdspan_types(handle, construct_mapping(layout, std::extents()), acc); + test_mdspan_types(handle, construct_mapping(layout, std::extents(7)), acc); + test_mdspan_types(handle, construct_mapping(layout, std::extents()), acc); + test_mdspan_types(handle, construct_mapping(layout, std::extents(2, 3)), acc); + test_mdspan_types(handle, construct_mapping(layout, std::extents(0, 3)), acc); + test_mdspan_types(handle, construct_mapping(layout, std::extents(1, 2, 3, 2)), acc); +} + +template +constexpr void mixin_layout(const H& handle, const A& acc) { + mixin_extents(handle, std::layout_left(), acc); + mixin_extents(handle, std::layout_right(), acc); + mixin_extents(handle, layout_wrapping_integral<4>(), acc); +} + +template +constexpr void mixin_accessor() { + ElementPool elements; + mixin_layout(elements.get_ptr(), std::default_accessor()); + + // Using weird accessor/data_handle + // Make sure they actually got the properties we want to test + // checked_accessor is noexcept copy constructible except for const double + checked_accessor acc(1024); + static_assert(noexcept(checked_accessor(acc)) != std::is_same_v); + mixin_layout(typename checked_accessor::data_handle_type(elements.get_ptr()), acc); +} + +constexpr bool test() { + mixin_accessor(); + mixin_accessor(); + mixin_accessor(); + mixin_accessor(); + mixin_accessor(); + mixin_accessor(); + return true; +} +int main(int, char**) { + (void)test(); + static_assert(test()); + return 0; +} Index: libcxx/test/std/containers/views/mdspan/mdspan/ctor.default.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/containers/views/mdspan/mdspan/ctor.default.pass.cpp @@ -0,0 +1,106 @@ +//===----------------------------------------------------------------------===// +// +// 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 mdspan(); +// Constraints: +// - rank_dynamic() > 0 is true. +// - is_default_constructible_v is true. +// - is_default_constructible_v is true. +// - is_default_constructible_v is true. +// +// Preconditions: [0, map_.required_span_size()) is an accessible range of ptr_ +// and acc_ for the values of map_ and acc_ after the invocation of this constructor. +// +// Effects: Value-initializes ptr_, map_, and acc_. + +#include +#include +#include +#include + +#include "test_macros.h" + +#include "../MinimalElementType.h" +#include "CustomTestLayouts.h" +#include "CustomTestAccessors.h" + +template +constexpr void test_mdspan_types(const H&, const M&, const A&) { + using MDS = std::mdspan; + + if constexpr (MDS::rank_dynamic() > 0 && std::is_default_constructible_v && std::is_default_constructible_v && + std::is_default_constructible_v) { + MDS m; + static_assert(noexcept(MDS()) == (noexcept(H())&& noexcept(M())&& noexcept(A()))); + assert(m.extents() == typename MDS::extents_type()); + if constexpr (std::equality_comparable) + assert(m.data_handle() == H()); + if constexpr (std::equality_comparable) + assert(m.mapping() == M()); + if constexpr (std::equality_comparable) + assert(m.accessor() == A()); + } else { + static_assert(!std::is_default_constructible_v); + } +} + +template +constexpr void mixin_extents(const H& handle, const L& layout, const A& acc) { + constexpr size_t D = std::dynamic_extent; + test_mdspan_types(handle, construct_mapping(layout, std::extents()), acc); + test_mdspan_types(handle, construct_mapping(layout, std::extents(7)), acc); + test_mdspan_types(handle, construct_mapping(layout, std::extents()), acc); + test_mdspan_types(handle, construct_mapping(layout, std::extents(2, 3)), acc); + test_mdspan_types(handle, construct_mapping(layout, std::extents(0, 3)), acc); + test_mdspan_types(handle, construct_mapping(layout, std::extents(1, 2, 3, 2)), acc); +} + +template +constexpr void mixin_layout(const H& handle, const A& acc) { + mixin_extents(handle, std::layout_left(), acc); + mixin_extents(handle, std::layout_right(), acc); + + // Use weird layout, make sure it has the properties we want to test + constexpr size_t D = std::dynamic_extent; + static_assert( + !std::is_default_constructible_v< typename layout_wrapping_integral<4>::template mapping>>); + mixin_extents(handle, layout_wrapping_integral<4>(), acc); +} + +template +constexpr void mixin_accessor() { + ElementPool elements; + mixin_layout(elements.get_ptr(), std::default_accessor()); + + // Using weird accessor/data_handle + // Make sure they actually got the properties we want to test + // checked_accessor is not default constructible except for const double, where it is not noexcept + static_assert(std::is_default_constructible_v> == std::is_same_v); + // checked_accessor's data handle type is not default constructible for double + static_assert( + std::is_default_constructible_v::data_handle_type> != std::is_same_v); + mixin_layout(typename checked_accessor::data_handle_type(elements.get_ptr()), checked_accessor(1024)); +} + +constexpr bool test() { + mixin_accessor(); + mixin_accessor(); + mixin_accessor(); + mixin_accessor(); + mixin_accessor(); + mixin_accessor(); + return true; +} +int main(int, char**) { + (void)test(); + static_assert(test()); + return 0; +} Index: libcxx/test/std/containers/views/mdspan/mdspan/ctor.dh_arrays.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/containers/views/mdspan/mdspan/ctor.dh_arrays.pass.cpp @@ -0,0 +1,119 @@ +//===----------------------------------------------------------------------===// +// +// 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(N != rank_dynamic()) +// mdspan(data_handle_type p, const array& exts); +// +// Constraints: +// - is_convertible_v is true, +// - (is_nothrow_constructible && ...) is true, +// - N == rank() || N == rank_dynamic() is true, +// - is_constructible_v is true, and +// - is_default_constructible_v is true. +// +// Preconditions: [0, map_.required_span_size()) is an accessible range of p and acc_ +// for the values of map_ and acc_ after the invocation of this constructor. +// +// Effects: +// - Direct-non-list-initializes ptr_ with std::move(p), +// - direct-non-list-initializes map_ with extents_type(exts), and +// - value-initializes acc_. + +#include +#include +#include +#include +#include + +#include "test_macros.h" + +#include "../MinimalElementType.h" +#include "CustomTestLayouts.h" +#include "CustomTestAccessors.h" + +template +constexpr auto array_from_extents(const Extents& exts, std::index_sequence) { + return std::array{exts.extent(Idxs)...}; +} + +template +constexpr void test_mdspan_types(const H& handle, const M& map, const A&) { + using MDS = std::mdspan; + + if constexpr (std::is_constructible_v && std::is_default_constructible_v) { + auto exts = array_from_extents(map.extents(), std::make_index_sequence()); + MDS m(handle, exts); + static_assert(!noexcept(MDS(handle, map.extents()))); + assert(m.extents() == map.extents()); + if constexpr (std::equality_comparable) + assert(m.data_handle() == handle); + if constexpr (std::equality_comparable) + assert(m.mapping() == map); + if constexpr (std::equality_comparable) + assert(m.accessor() == A()); + } else { + static_assert(!std::is_constructible_v); + } +} + +template +constexpr void mixin_extents(const H& handle, const L& layout, const A& acc) { + constexpr size_t D = std::dynamic_extent; + test_mdspan_types(handle, construct_mapping(layout, std::extents()), acc); + test_mdspan_types(handle, construct_mapping(layout, std::extents(7)), acc); + test_mdspan_types(handle, construct_mapping(layout, std::extents()), acc); + test_mdspan_types(handle, construct_mapping(layout, std::extents(2, 3)), acc); + test_mdspan_types(handle, construct_mapping(layout, std::extents(0, 3)), acc); + test_mdspan_types(handle, construct_mapping(layout, std::extents(1, 2, 3, 2)), acc); +} + +template +constexpr void mixin_layout(const H& handle, const A& acc) { + mixin_extents(handle, std::layout_left(), acc); + mixin_extents(handle, std::layout_right(), acc); + + // Use weird layout, make sure it has the properties we want to test + constexpr size_t D = std::dynamic_extent; + static_assert( + !std::is_default_constructible_v< typename layout_wrapping_integral<4>::template mapping>>); + mixin_extents(handle, layout_wrapping_integral<4>(), acc); +} + +template +constexpr void mixin_accessor() { + ElementPool elements; + mixin_layout(elements.get_ptr(), std::default_accessor()); + + // Using weird accessor/data_handle + // Make sure they actually got the properties we want to test + // checked_accessor is not default constructible except for const double, where it is not noexcept + static_assert(std::is_default_constructible_v> == std::is_same_v); + // checked_accessor's data handle type is not default constructible for double + static_assert( + std::is_default_constructible_v::data_handle_type> != std::is_same_v); + mixin_layout(typename checked_accessor::data_handle_type(elements.get_ptr()), checked_accessor(1024)); +} + +constexpr bool test() { + mixin_accessor(); + mixin_accessor(); + mixin_accessor(); + mixin_accessor(); + mixin_accessor(); + mixin_accessor(); + return true; +} +int main(int, char**) { + (void)test(); + static_assert(test()); + return 0; +} Index: libcxx/test/std/containers/views/mdspan/mdspan/ctor.dh_extents.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/containers/views/mdspan/mdspan/ctor.dh_extents.pass.cpp @@ -0,0 +1,107 @@ +//===----------------------------------------------------------------------===// +// +// 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 mdspan(data_handle_type p, const extents_type& ext); +// +// Constraints: +// - is_constructible_v is true, and +// - is_default_constructible_v is true. +// +// Preconditions: [0, map_.required_span_size()) is an accessible range of p and acc_ +// for the values of map_ and acc_ after the invocation of this constructor. +// +// Effects: +// - Direct-non-list-initializes ptr_ with std::move(p), +// - direct-non-list-initializes map_ with ext, and +// - value-initializes acc_. + +#include +#include +#include +#include + +#include "test_macros.h" + +#include "../MinimalElementType.h" +#include "CustomTestLayouts.h" +#include "CustomTestAccessors.h" + +template +constexpr void test_mdspan_types(const H& handle, const M& map, const A&) { + using MDS = std::mdspan; + + if constexpr (std::is_constructible_v && std::is_default_constructible_v) { + MDS m(handle, map.extents()); + static_assert(!noexcept(MDS(handle, map.extents()))); + assert(m.extents() == map.extents()); + if constexpr (std::equality_comparable) + assert(m.data_handle() == handle); + if constexpr (std::equality_comparable) + assert(m.mapping() == map); + if constexpr (std::equality_comparable) + assert(m.accessor() == A()); + } else { + static_assert(!std::is_constructible_v); + } +} + +template +constexpr void mixin_extents(const H& handle, const L& layout, const A& acc) { + constexpr size_t D = std::dynamic_extent; + test_mdspan_types(handle, construct_mapping(layout, std::extents()), acc); + test_mdspan_types(handle, construct_mapping(layout, std::extents(7)), acc); + test_mdspan_types(handle, construct_mapping(layout, std::extents()), acc); + test_mdspan_types(handle, construct_mapping(layout, std::extents(2, 3)), acc); + test_mdspan_types(handle, construct_mapping(layout, std::extents(0, 3)), acc); + test_mdspan_types(handle, construct_mapping(layout, std::extents(1, 2, 3, 2)), acc); +} + +template +constexpr void mixin_layout(const H& handle, const A& acc) { + mixin_extents(handle, std::layout_left(), acc); + mixin_extents(handle, std::layout_right(), acc); + + // Use weird layout, make sure it has the properties we want to test + constexpr size_t D = std::dynamic_extent; + static_assert( + !std::is_default_constructible_v< typename layout_wrapping_integral<4>::template mapping>>); + mixin_extents(handle, layout_wrapping_integral<4>(), acc); +} + +template +constexpr void mixin_accessor() { + ElementPool elements; + mixin_layout(elements.get_ptr(), std::default_accessor()); + + // Using weird accessor/data_handle + // Make sure they actually got the properties we want to test + // checked_accessor is not default constructible except for const double, where it is not noexcept + static_assert(std::is_default_constructible_v> == std::is_same_v); + // checked_accessor's data handle type is not default constructible for double + static_assert( + std::is_default_constructible_v::data_handle_type> != std::is_same_v); + mixin_layout(typename checked_accessor::data_handle_type(elements.get_ptr()), checked_accessor(1024)); +} + +constexpr bool test() { + mixin_accessor(); + mixin_accessor(); + mixin_accessor(); + mixin_accessor(); + mixin_accessor(); + mixin_accessor(); + return true; +} +int main(int, char**) { + (void)test(); + static_assert(test()); + return 0; +} Index: libcxx/test/std/containers/views/mdspan/mdspan/ctor.dh_integers.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/containers/views/mdspan/mdspan/ctor.dh_integers.pass.cpp @@ -0,0 +1,121 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template +// constexpr explicit mdspan(data_handle_type p, OtherIndexTypes... exts); +// +// Let N be sizeof...(OtherIndexTypes). +// +// Constraints: +// - (is_convertible_v && ...) is true, +// - (is_nothrow_constructible && ...) is true, +// - N == rank() || N == rank_dynamic() is true, +// - is_constructible_v is true, and +// - is_default_constructible_v is true. +// +// Preconditions: [0, map_.required_span_size()) is an accessible range of p and acc_ +// for the values of map_ and acc_ after the invocation of this constructor. +// +// Effects: +// - Direct-non-list-initializes ptr_ with std::move(p), +// - direct-non-list-initializes map_ with extents_type(static_cast(std::move(exts))...), and +// - value-initializes acc_. + +#include +#include +#include +#include +#include + +#include "test_macros.h" + +#include "../MinimalElementType.h" +#include "CustomTestLayouts.h" +#include "CustomTestAccessors.h" + +template +constexpr auto +mdspan_from_integers(const typename MDS::data_handle_type& handle, const Extents& exts, std::index_sequence) { + static_assert(!noexcept(MDS(handle, exts.extent(Idxs)...))); + return MDS(handle, exts.extent(Idxs)...); +} + +template +constexpr void test_mdspan_types(const H& handle, const M& map, const A&) { + using MDS = std::mdspan; + + if constexpr (std::is_constructible_v && std::is_default_constructible_v) { + auto m = mdspan_from_integers(handle, map.extents(), std::make_index_sequence()); + assert(m.extents() == map.extents()); + if constexpr (std::equality_comparable) + assert(m.data_handle() == handle); + if constexpr (std::equality_comparable) + assert(m.mapping() == map); + if constexpr (std::equality_comparable) + assert(m.accessor() == A()); + } else { + static_assert(!std::is_constructible_v); + } +} + +template +constexpr void mixin_extents(const H& handle, const L& layout, const A& acc) { + constexpr size_t D = std::dynamic_extent; + test_mdspan_types(handle, construct_mapping(layout, std::extents()), acc); + test_mdspan_types(handle, construct_mapping(layout, std::extents(7)), acc); + test_mdspan_types(handle, construct_mapping(layout, std::extents()), acc); + test_mdspan_types(handle, construct_mapping(layout, std::extents(2, 3)), acc); + test_mdspan_types(handle, construct_mapping(layout, std::extents(0, 3)), acc); + test_mdspan_types(handle, construct_mapping(layout, std::extents(1, 2, 3, 2)), acc); +} + +template +constexpr void mixin_layout(const H& handle, const A& acc) { + mixin_extents(handle, std::layout_left(), acc); + mixin_extents(handle, std::layout_right(), acc); + + // Use weird layout, make sure it has the properties we want to test + constexpr size_t D = std::dynamic_extent; + static_assert( + !std::is_default_constructible_v< typename layout_wrapping_integral<4>::template mapping>>); + mixin_extents(handle, layout_wrapping_integral<4>(), acc); +} + +template +constexpr void mixin_accessor() { + ElementPool elements; + mixin_layout(elements.get_ptr(), std::default_accessor()); + + // Using weird accessor/data_handle + // Make sure they actually got the properties we want to test + // checked_accessor is not default constructible except for const double, where it is not noexcept + static_assert(std::is_default_constructible_v> == std::is_same_v); + // checked_accessor's data handle type is not default constructible for double + static_assert( + std::is_default_constructible_v::data_handle_type> != std::is_same_v); + mixin_layout(typename checked_accessor::data_handle_type(elements.get_ptr()), checked_accessor(1024)); +} + +constexpr bool test() { + mixin_accessor(); + mixin_accessor(); + mixin_accessor(); + mixin_accessor(); + mixin_accessor(); + mixin_accessor(); + return true; +} + +int main(int, char**) { + (void)test(); + static_assert(test()); + return 0; +} Index: libcxx/test/std/containers/views/mdspan/mdspan/ctor.dh_map.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/containers/views/mdspan/mdspan/ctor.dh_map.pass.cpp @@ -0,0 +1,105 @@ +//===----------------------------------------------------------------------===// +// +// 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 mdspan(data_handle_type p, const mapping_type& m); +// +// Constraints: is_default_constructible_v is true. +// +// Preconditions: [0, m.required_span_size()) is an accessible range of p and acc_ +// for the value of acc_ after the invocation of this constructor. +// +// Effects: +// - Direct-non-list-initializes ptr_ with std::move(p), +// - direct-non-list-initializes map_ with m, and +// - value-initializes acc_. + +#include +#include +#include +#include + +#include "test_macros.h" + +#include "../MinimalElementType.h" +#include "CustomTestLayouts.h" +#include "CustomTestAccessors.h" + +template +constexpr void test_mdspan_types(const H& handle, const M& map, const A&) { + using MDS = std::mdspan; + + if constexpr (std::is_default_constructible_v) { + MDS m(handle, map); + static_assert(!noexcept(MDS(handle, map))); + assert(m.extents() == map.extents()); + if constexpr (std::equality_comparable) + assert(m.data_handle() == handle); + if constexpr (std::equality_comparable) + assert(m.mapping() == map); + if constexpr (std::equality_comparable) + assert(m.accessor() == A()); + } else { + static_assert(!std::is_constructible_v); + } +} + +template +constexpr void mixin_extents(const H& handle, const L& layout, const A& acc) { + constexpr size_t D = std::dynamic_extent; + test_mdspan_types(handle, construct_mapping(layout, std::extents()), acc); + test_mdspan_types(handle, construct_mapping(layout, std::extents(7)), acc); + test_mdspan_types(handle, construct_mapping(layout, std::extents()), acc); + test_mdspan_types(handle, construct_mapping(layout, std::extents(2, 3)), acc); + test_mdspan_types(handle, construct_mapping(layout, std::extents(0, 3)), acc); + test_mdspan_types(handle, construct_mapping(layout, std::extents(1, 2, 3, 2)), acc); +} + +template +constexpr void mixin_layout(const H& handle, const A& acc) { + mixin_extents(handle, std::layout_left(), acc); + mixin_extents(handle, std::layout_right(), acc); + + // Use weird layout, make sure it has the properties we want to test + constexpr size_t D = std::dynamic_extent; + static_assert( + !std::is_default_constructible_v< typename layout_wrapping_integral<4>::template mapping>>); + mixin_extents(handle, layout_wrapping_integral<4>(), acc); +} + +template +constexpr void mixin_accessor() { + ElementPool elements; + mixin_layout(elements.get_ptr(), std::default_accessor()); + + // Using weird accessor/data_handle + // Make sure they actually got the properties we want to test + // checked_accessor is not default constructible except for const double, where it is not noexcept + static_assert(std::is_default_constructible_v> == std::is_same_v); + // checked_accessor's data handle type is not default constructible for double + static_assert( + std::is_default_constructible_v::data_handle_type> != std::is_same_v); + mixin_layout(typename checked_accessor::data_handle_type(elements.get_ptr()), checked_accessor(1024)); +} + +constexpr bool test() { + mixin_accessor(); + mixin_accessor(); + mixin_accessor(); + mixin_accessor(); + mixin_accessor(); + mixin_accessor(); + return true; +} +int main(int, char**) { + (void)test(); + static_assert(test()); + return 0; +} Index: libcxx/test/std/containers/views/mdspan/mdspan/ctor.dh_map_acc.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/containers/views/mdspan/mdspan/ctor.dh_map_acc.pass.cpp @@ -0,0 +1,98 @@ +//===----------------------------------------------------------------------===// +// +// 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 mdspan(data_handle_type p, const mapping_type& m, const accessor_type& a); +// +// Preconditions: [0, m.required_span_size()) is an accessible range of p and a. +// +// Effects: +// - Direct-non-list-initializes ptr_ with std::move(p), +// - direct-non-list-initializes map_ with m, and +// - direct-non-list-initializes acc_ with a. + +#include +#include +#include +#include + +#include "test_macros.h" + +#include "../MinimalElementType.h" +#include "CustomTestLayouts.h" +#include "CustomTestAccessors.h" + +template +constexpr void test_mdspan_types(const H& handle, const M& map, const A& acc) { + using MDS = std::mdspan; + + MDS m(handle, map, acc); + static_assert(!noexcept(MDS(handle, map, acc))); + assert(m.extents() == map.extents()); + if constexpr (std::equality_comparable) + assert(m.data_handle() == handle); + if constexpr (std::equality_comparable) + assert(m.mapping() == map); + if constexpr (std::equality_comparable) + assert(m.accessor() == acc); +} + +template +constexpr void mixin_extents(const H& handle, const L& layout, const A& acc) { + constexpr size_t D = std::dynamic_extent; + test_mdspan_types(handle, construct_mapping(layout, std::extents()), acc); + test_mdspan_types(handle, construct_mapping(layout, std::extents(7)), acc); + test_mdspan_types(handle, construct_mapping(layout, std::extents()), acc); + test_mdspan_types(handle, construct_mapping(layout, std::extents(2, 3)), acc); + test_mdspan_types(handle, construct_mapping(layout, std::extents(0, 3)), acc); + test_mdspan_types(handle, construct_mapping(layout, std::extents(1, 2, 3, 2)), acc); +} + +template +constexpr void mixin_layout(const H& handle, const A& acc) { + mixin_extents(handle, std::layout_left(), acc); + mixin_extents(handle, std::layout_right(), acc); + + // Use weird layout, make sure it has the properties we want to test + constexpr size_t D = std::dynamic_extent; + static_assert( + !std::is_default_constructible_v< typename layout_wrapping_integral<4>::template mapping>>); + mixin_extents(handle, layout_wrapping_integral<4>(), acc); +} + +template +constexpr void mixin_accessor() { + ElementPool elements; + mixin_layout(elements.get_ptr(), std::default_accessor()); + + // Using weird accessor/data_handle + // Make sure they actually got the properties we want to test + // checked_accessor is not default constructible except for const double, where it is not noexcept + static_assert(std::is_default_constructible_v> == std::is_same_v); + // checked_accessor's data handle type is not default constructible for double + static_assert( + std::is_default_constructible_v::data_handle_type> != std::is_same_v); + mixin_layout(typename checked_accessor::data_handle_type(elements.get_ptr()), checked_accessor(1024)); +} + +constexpr bool test() { + mixin_accessor(); + mixin_accessor(); + mixin_accessor(); + mixin_accessor(); + mixin_accessor(); + mixin_accessor(); + return true; +} +int main(int, char**) { + (void)test(); + static_assert(test()); + return 0; +} Index: libcxx/test/std/containers/views/mdspan/mdspan/ctor.dh_span.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/containers/views/mdspan/mdspan/ctor.dh_span.pass.cpp @@ -0,0 +1,121 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template +// constexpr explicit(N != rank_dynamic()) +// mdspan(data_handle_type p, const span& exts); +// +// Constraints: +// - is_convertible_v is true, +// - (is_nothrow_constructible && ...) is true, +// - N == rank() || N == rank_dynamic() is true, +// - is_constructible_v is true, and +// - is_default_constructible_v is true. +// +// Preconditions: [0, map_.required_span_size()) is an accessible range of p and acc_ +// for the values of map_ and acc_ after the invocation of this constructor. +// +// Effects: +// - Direct-non-list-initializes ptr_ with std::move(p), +// - direct-non-list-initializes map_ with extents_type(exts), and +// - value-initializes acc_. + +#include +#include +#include +#include +#include +#include + +#include "test_macros.h" + +#include "../MinimalElementType.h" +#include "CustomTestLayouts.h" +#include "CustomTestAccessors.h" + +template +constexpr auto array_from_extents(const Extents& exts, std::index_sequence) { + return std::array{exts.extent(Idxs)...}; +} + +template +constexpr void test_mdspan_types(const H& handle, const M& map, const A&) { + using MDS = std::mdspan; + + if constexpr (std::is_constructible_v && std::is_default_constructible_v) { + auto exts_arr = array_from_extents(map.extents(), std::make_index_sequence()); + std::span exts(exts_arr); + MDS m(handle, exts); + static_assert(!noexcept(MDS(handle, map.extents()))); + assert(m.extents() == map.extents()); + if constexpr (std::equality_comparable) + assert(m.data_handle() == handle); + if constexpr (std::equality_comparable) + assert(m.mapping() == map); + if constexpr (std::equality_comparable) + assert(m.accessor() == A()); + } else { + static_assert(!std::is_constructible_v); + } +} + +template +constexpr void mixin_extents(const H& handle, const L& layout, const A& acc) { + constexpr size_t D = std::dynamic_extent; + test_mdspan_types(handle, construct_mapping(layout, std::extents()), acc); + test_mdspan_types(handle, construct_mapping(layout, std::extents(7)), acc); + test_mdspan_types(handle, construct_mapping(layout, std::extents()), acc); + test_mdspan_types(handle, construct_mapping(layout, std::extents(2, 3)), acc); + test_mdspan_types(handle, construct_mapping(layout, std::extents(0, 3)), acc); + test_mdspan_types(handle, construct_mapping(layout, std::extents(1, 2, 3, 2)), acc); +} + +template +constexpr void mixin_layout(const H& handle, const A& acc) { + mixin_extents(handle, std::layout_left(), acc); + mixin_extents(handle, std::layout_right(), acc); + + // Use weird layout, make sure it has the properties we want to test + constexpr size_t D = std::dynamic_extent; + static_assert( + !std::is_default_constructible_v< typename layout_wrapping_integral<4>::template mapping>>); + mixin_extents(handle, layout_wrapping_integral<4>(), acc); +} + +template +constexpr void mixin_accessor() { + ElementPool elements; + mixin_layout(elements.get_ptr(), std::default_accessor()); + + // Using weird accessor/data_handle + // Make sure they actually got the properties we want to test + // checked_accessor is not default constructible except for const double, where it is not noexcept + static_assert(std::is_default_constructible_v> == std::is_same_v); + // checked_accessor's data handle type is not default constructible for double + static_assert( + std::is_default_constructible_v::data_handle_type> != std::is_same_v); + mixin_layout(typename checked_accessor::data_handle_type(elements.get_ptr()), checked_accessor(1024)); +} + +constexpr bool test() { + mixin_accessor(); + mixin_accessor(); + mixin_accessor(); + mixin_accessor(); + mixin_accessor(); + mixin_accessor(); + return true; +} +int main(int, char**) { + (void)test(); + static_assert(test()); + return 0; +} Index: libcxx/test/std/containers/views/mdspan/mdspan/deduction.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/containers/views/mdspan/mdspan/deduction.pass.cpp @@ -0,0 +1,159 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// requires(is_array_v && rank_v == 1) +// mdspan(CArray&) +// -> mdspan, extents>>; +// +// template +// requires(is_pointer_v>) +// mdspan(Pointer&&) +// -> mdspan>, extents>; +// +// template +// requires((is_convertible_v && ...) && sizeof...(Integrals) > 0) +// explicit mdspan(ElementType*, Integrals...) +// -> mdspan>; +// +// template +// mdspan(ElementType*, span) +// -> mdspan>; +// +// template +// mdspan(ElementType*, const array&) +// -> mdspan>; +// +// template +// mdspan(ElementType*, const extents&) +// -> mdspan>; +// +// template +// mdspan(ElementType*, const MappingType&) +// -> mdspan; +// +// template +// mdspan(const typename AccessorType::data_handle_type&, const MappingType&, +// const AccessorType&) +// -> mdspan; + +#include +#include +#include +#include + +#include "test_macros.h" + +#include "../MinimalElementType.h" +#include "CustomTestLayouts.h" +#include "CustomTestAccessors.h" + +template +constexpr void test_mdspan_types(const H& handle, const M& map, const A& acc) { + using MDS = std::mdspan; + + // deduction from data_handle_type (including non-pointer), mapping and accessor + ASSERT_SAME_TYPE(decltype(std::mdspan(handle, map, acc)), MDS); + + if constexpr (std::is_same_v>) { + // deduction from pointer and mapping + // non-pointer data-handle-types have other accessor + ASSERT_SAME_TYPE(decltype(std::mdspan(handle, map)), MDS); + if constexpr (std::is_same_v) { + // deduction from pointer and extents + ASSERT_SAME_TYPE(decltype(std::mdspan(handle, map.extents())), MDS); + } + } +} + +template +constexpr void mixin_extents(const H& handle, const L& layout, const A& acc) { + constexpr size_t D = std::dynamic_extent; + test_mdspan_types(handle, construct_mapping(layout, std::extents()), acc); + test_mdspan_types(handle, construct_mapping(layout, std::extents(7)), acc); + test_mdspan_types(handle, construct_mapping(layout, std::extents()), acc); + test_mdspan_types(handle, construct_mapping(layout, std::extents(2, 3)), acc); + test_mdspan_types(handle, construct_mapping(layout, std::extents(0, 3)), acc); + test_mdspan_types(handle, construct_mapping(layout, std::extents(1, 2, 3, 2)), acc); +} + +struct SizeTIntType { + size_t val; + constexpr SizeTIntType(size_t val_) : val(val_) {} + constexpr operator size_t() const noexcept { return size_t(val); } +}; + +template + requires(sizeof(decltype(std::mdspan(std::declval(), 10))) > 0) +constexpr bool test_no_layout_deduction_guides(const H& handle, const A&) { + using T = typename A::element_type; + // deduction from pointer alone + ASSERT_SAME_TYPE(decltype(std::mdspan(handle)), std::mdspan>); + // deduction from pointer and integral like + ASSERT_SAME_TYPE(decltype(std::mdspan(handle, 5, SizeTIntType(6))), std::mdspan>); + + std::array exts; + // deduction from pointer and array + ASSERT_SAME_TYPE(decltype(std::mdspan(handle, exts)), std::mdspan>); + // deduction from pointer and span + ASSERT_SAME_TYPE(decltype(std::mdspan(handle, std::span(exts))), std::mdspan>); + return true; +} + +template +constexpr bool test_no_layout_deduction_guides(const H&, const A&) { + return false; +} + +template +constexpr void mixin_layout(const H& handle, const A& acc) { + mixin_extents(handle, std::layout_left(), acc); + mixin_extents(handle, std::layout_right(), acc); + mixin_extents(handle, layout_wrapping_integral<4>(), acc); + + // checking that there is no deduction happen for non-pointer handle type + assert((test_no_layout_deduction_guides(handle, acc) == std::is_same_v)); +} + +template +constexpr void mixin_accessor() { + ElementPool elements; + mixin_layout(elements.get_ptr(), std::default_accessor()); + + // Using weird accessor/data_handle + // Make sure they actually got the properties we want to test + // checked_accessor is noexcept copy constructible except for const double + checked_accessor acc(1024); + static_assert(noexcept(checked_accessor(acc)) != std::is_same_v); + mixin_layout(typename checked_accessor::data_handle_type(elements.get_ptr()), acc); +} + +constexpr bool test() { + mixin_accessor(); + mixin_accessor(); + mixin_accessor(); + mixin_accessor(); + mixin_accessor(); + mixin_accessor(); + + // deduction from array alone + float a[12]; + ASSERT_SAME_TYPE(decltype(std::mdspan(a)), std::mdspan>); + + return true; +} +int main(int, char**) { + (void)test(); + static_assert(test()); + return 0; +} Index: libcxx/test/std/containers/views/mdspan/mdspan/element_type.verify.cpp =================================================================== --- /dev/null +++ libcxx/test/std/containers/views/mdspan/mdspan/element_type.verify.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 +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template +// class mdspan; +// +// Mandates: +// - ElementType is a complete object type that is neither an abstract class type nor an array type. +// - is_same_v is true. + +#include + +class AbstractClass { +public: + virtual void method() = 0; +}; + +void not_abstract_class() { + // expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}mdspan: ElementType template parameter may not be an abstract class}} + [[maybe_unused]] std::mdspan> m; +} + +void not_array_type() { + // expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}mdspan: ElementType template parameter may not be an array type}} + [[maybe_unused]] std::mdspan> m; +} + +void element_type_mismatch() { + // expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}mdspan: ElementType template parameter must match AccessorPolicy::element_type}} + [[maybe_unused]] std::mdspan, std::layout_right, std::default_accessor> m; +} Index: libcxx/test/std/containers/views/mdspan/mdspan/extents.verify.cpp =================================================================== --- /dev/null +++ libcxx/test/std/containers/views/mdspan/mdspan/extents.verify.cpp @@ -0,0 +1,24 @@ +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template +// class mdspan; +// +// Mandates: +// - Extents is a specialization of extents + +#include + + +void not_extents() { + // expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}mdspan: Extents template parameter must be a specialization of extents.}} + [[maybe_unused]] std::mdspan m; +} Index: libcxx/test/std/containers/views/mdspan/mdspan/index_operator.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/containers/views/mdspan/mdspan/index_operator.pass.cpp @@ -0,0 +1,181 @@ +//===----------------------------------------------------------------------===// +// +// 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 reference 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_. + +// GCC warns about comma operator changing its meaning inside [] in C++23 +#if defined(__GNUC__) && !defined(__clang_major__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcomma-subscript" +#endif + +#include +#include +#include + +#include "test_macros.h" + +#include "../ConvertibleToIntegral.h" +#include "CustomTestLayouts.h" + +// Clang 15 and 16 do not support argument packs as input to operator [] +#if defined(__clang_major__) && __clang_major__ < 17 +template +constexpr auto& access(MDS mds) { + return mds[]; +} +template +constexpr auto& access(MDS mds, int64_t i0) { + return mds[i0]; +} +template +constexpr auto& access(MDS mds, int64_t i0, int64_t i1) { + return mds[i0, i1]; +} +template +constexpr auto& access(MDS mds, int64_t i0, int64_t i1, int64_t i2) { + return mds[i0, i1, i2]; +} +template +constexpr auto& access(MDS mds, int64_t i0, int64_t i1, int64_t i2, int64_t i3) { + return mds[i0, i1, i2, i3]; +} +#endif + +template +concept operator_constraints = requires(MDS m, Indices... idxs) { + { std::is_same_v }; +}; + +template + requires(operator_constraints) +constexpr bool check_operator_constraints(MDS m, Indices... idxs) { + (void)m[idxs...]; + return true; +} + +template +constexpr bool check_operator_constraints(MDS, Indices...) { + return false; +} + +template +constexpr void iterate(MDS mds, Args... args) { + constexpr int r = static_cast(MDS::extents_type::rank()) - 1 - static_cast(sizeof...(Args)); + if constexpr (-1 == r) { +#if defined(__clang_major__) && __clang_major__ < 17 + int* ptr1 = &access(mds, args...); +#else + int* ptr1 = &mds[args...]; +#endif + int* ptr2 = &(mds.accessor().access(mds.data_handle(), mds.mapping()(args...))); + assert(ptr1 == ptr2); + } else { + for (typename MDS::index_type i = 0; i < mds.extents().extent(r); i++) { + iterate(mds, i, args...); + } + } +} + +template +constexpr void test_iteration(Mapping m) { + std::array data; + using MDS = std::mdspan; + MDS mds(data.data(), m); + + iterate(mds); +} + +template +constexpr void test_layout() { + constexpr size_t D = std::dynamic_extent; + test_iteration(construct_mapping(Layout(), std::extents())); + test_iteration(construct_mapping(Layout(), std::extents(1))); + test_iteration(construct_mapping(Layout(), std::extents(7))); + test_iteration(construct_mapping(Layout(), std::extents())); + test_iteration(construct_mapping(Layout(), std::extents())); + test_iteration(construct_mapping(Layout(), std::extents(1, 1, 1, 1))); + +#if !defined(__clang_major__) || __clang_major__ > 16 + int data[1]; + // Check operator constraint for number of arguments + static_assert(check_operator_constraints(std::mdspan(data, construct_mapping(Layout(), std::extents(1))), 0)); + static_assert( + !check_operator_constraints(std::mdspan(data, construct_mapping(Layout(), std::extents(1))), 0, 0)); + + // Check operator constraint for convertibility of arguments to index_type + static_assert( + check_operator_constraints(std::mdspan(data, construct_mapping(Layout(), std::extents(1))), IntType(0))); + static_assert(!check_operator_constraints( + std::mdspan(data, construct_mapping(Layout(), std::extents(1))), IntType(0))); + + // Check operator constraint for no-throw-constructibility of index_type from arguments + static_assert(!check_operator_constraints( + std::mdspan(data, construct_mapping(Layout(), std::extents(1))), IntType(0))); + + // Check that mixed integrals work: note the second one tests that mdspan casts: layout_wrapping_integral does not accept IntType + static_assert(check_operator_constraints( + std::mdspan(data, construct_mapping(Layout(), std::extents(1, 1))), int(0), size_t(0))); + static_assert(check_operator_constraints( + std::mdspan(data, construct_mapping(Layout(), std::extents(1, 1))), unsigned(0), IntType(0))); +#endif +} + +template +constexpr void test_layout_large() { + constexpr size_t D = std::dynamic_extent; + test_iteration(construct_mapping(Layout(), std::extents(3, 5, 6))); + test_iteration(construct_mapping(Layout(), std::extents(3, 6))); +} + +// mdspan::operator[] casts to index_type before calling mapping +// mapping requirements only require the index operator to mixed integer types not anything convertible to index_type +constexpr void test_index_cast_happens() {} + +constexpr bool test() { + test_layout(); + test_layout(); + test_layout>(); + return true; +} + +constexpr bool test_large() { + test_layout_large(); + test_layout_large(); + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + // The large test iterates over ~10k loop indices. + // With assertions enabled this triggered the maximum default limit + // for steps in consteval expressions. Assertions roughly double the + // total number of instructions, so this was already close to the maximum. + test_large(); + return 0; +} +#if defined(__GNUC__) && !defined(__clang_major__) +#pragma GCC diagnostic pop +#endif Index: libcxx/test/std/containers/views/mdspan/mdspan/mapping.verify.cpp =================================================================== --- /dev/null +++ libcxx/test/std/containers/views/mdspan/mdspan/mapping.verify.cpp @@ -0,0 +1,24 @@ +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template +// class mdspan; +// +// Mandates: +// - LayoutPolicy shall meet the layout mapping policy requirements ([mdspan.layout.policy.reqmts]) + +#include + + +void not_extents() { + // expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}mdspan: likely passed layout mapping template parameter instead of layout policy}} + [[maybe_unused]] std::mdspan, std::layout_left::template mapping>> m; +} Index: libcxx/test/std/containers/views/mdspan/mdspan/properties.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/containers/views/mdspan/mdspan/properties.pass.cpp @@ -0,0 +1,186 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template +// class extents { +// public: +// // types +// using index_type = IndexType; +// using size_type = make_unsigned_t; +// using rank_type = size_t; +// +// static constexpr rank_type rank() noexcept { return sizeof...(Extents); } +// static constexpr rank_type rank_dynamic() noexcept { return dynamic-index(rank()); } +// ... +// } + +#include +#include +#include +#include + +#include "test_macros.h" + +#include "../MinimalElementType.h" +#include "CustomTestLayouts.h" + +template +constexpr void test_mdspan_types(const H& handle, const M& map, const A& acc) { + using MDS = std::mdspan; + MDS m(handle, map, acc); + + // ===================================== + // Traits for every mdspan + // ===================================== + static_assert(std::copyable); + static_assert(std::is_nothrow_move_constructible_v); + static_assert(std::is_nothrow_move_assignable_v); + static_assert(std::is_nothrow_swappable_v); + + // ===================================== + // Invariants coming from data handle + // ===================================== + // data_handle() + ASSERT_SAME_TYPE(decltype(m.data_handle()), const H&); + ASSERT_NOEXCEPT(m.data_handle()); + if constexpr (std::equality_comparable) { + assert(m.data_handle() == handle); + } + + // ===================================== + // Invariants coming from extents + // ===================================== + + // extents() + ASSERT_SAME_TYPE(decltype(m.extents()), const typename MDS::extents_type&); + ASSERT_NOEXCEPT(m.extents()); + assert(m.extents() == map.extents()); + + // rank() + ASSERT_SAME_TYPE(decltype(m.rank()), typename MDS::rank_type); + ASSERT_NOEXCEPT(m.rank()); + static_assert(MDS::rank() == MDS::extents_type::rank()); + + // rank_dynamic() + ASSERT_SAME_TYPE(decltype(m.rank_dynamic()), typename MDS::rank_type); + ASSERT_NOEXCEPT(m.rank_dynamic()); + static_assert(MDS::rank_dynamic() == MDS::extents_type::rank_dynamic()); + + // extent(r), static_extent(r), size() + if constexpr (MDS::rank() > 0) { + typename MDS::size_type size = 1; + for (typename MDS::rank_type r = 0; r < MDS::rank(); r++) { + ASSERT_SAME_TYPE(decltype(MDS::static_extent(r)), size_t); + ASSERT_NOEXCEPT(MDS::static_extent(r)); + assert(MDS::static_extent(r) == MDS::extents_type::static_extent(r)); + ASSERT_SAME_TYPE(decltype(m.extent(r)), typename MDS::index_type); + ASSERT_NOEXCEPT(m.extent(r)); + assert(m.extent(r) == m.extents().extent(r)); + size *= m.extent(r); + } + assert(m.size() == size); + } else { + assert(m.size() == 1); + } + ASSERT_SAME_TYPE(decltype(m.size()), typename MDS::size_type); + ASSERT_NOEXCEPT(m.size()); + + // empty() + ASSERT_SAME_TYPE(decltype(m.empty()), bool); + ASSERT_NOEXCEPT(m.empty()); + assert(m.empty() == (m.size() == 0)); + + // ===================================== + // Invariants coming from mapping + // ===================================== + + // mapping() + ASSERT_SAME_TYPE(decltype(m.mapping()), const M&); + ASSERT_NOEXCEPT(m.mapping()); + + // is_[always_]unique/exhaustive/strided() + ASSERT_SAME_TYPE(decltype(MDS::is_always_unique()), bool); + ASSERT_SAME_TYPE(decltype(MDS::is_always_exhaustive()), bool); + ASSERT_SAME_TYPE(decltype(MDS::is_always_strided()), bool); + ASSERT_SAME_TYPE(decltype(m.is_unique()), bool); + ASSERT_SAME_TYPE(decltype(m.is_exhaustive()), bool); + ASSERT_SAME_TYPE(decltype(m.is_strided()), bool); + assert(!noexcept(MDS::is_always_unique())); + assert(!noexcept(MDS::is_always_exhaustive())); + assert(!noexcept(MDS::is_always_strided())); + assert(!noexcept(m.is_unique())); + assert(!noexcept(m.is_exhaustive())); + assert(!noexcept(m.is_strided())); + static_assert(MDS::is_always_unique() == M::is_always_unique()); + static_assert(MDS::is_always_exhaustive() == M::is_always_exhaustive()); + static_assert(MDS::is_always_strided() == M::is_always_strided()); + assert(m.is_unique() == map.is_unique()); + assert(m.is_exhaustive() == map.is_exhaustive()); + assert(m.is_strided() == map.is_strided()); + + // stride(r) + if constexpr (MDS::rank() > 0) { + if (m.is_strided()) { + for (typename MDS::rank_type r = 0; r < MDS::rank(); r++) { + ASSERT_SAME_TYPE(decltype(m.stride(r)), typename MDS::index_type); + assert(!noexcept(m.stride(r))); + assert(m.stride(r) == map.stride(r)); + } + } + } + + // ===================================== + // Invariants coming from accessor + // ===================================== + + // accessor() + ASSERT_SAME_TYPE(decltype(m.accessor()), const A&); + ASSERT_NOEXCEPT(m.accessor()); +} + +template +constexpr void mixin_extents(const H& handle, const L& layout, const A& acc) { + constexpr size_t D = std::dynamic_extent; + test_mdspan_types(handle, construct_mapping(layout, std::extents()), acc); + test_mdspan_types(handle, construct_mapping(layout, std::extents(7)), acc); + test_mdspan_types(handle, construct_mapping(layout, std::extents()), acc); + test_mdspan_types(handle, construct_mapping(layout, std::extents(2, 3)), acc); + test_mdspan_types(handle, construct_mapping(layout, std::extents(0, 3)), acc); + test_mdspan_types(handle, construct_mapping(layout, std::extents(1, 2, 3, 2)), acc); +} + +template +constexpr void mixin_layout(const H& handle, const A& acc) { + mixin_extents(handle, std::layout_left(), acc); + mixin_extents(handle, std::layout_right(), acc); + mixin_extents(handle, layout_wrapping_integral<4>(), acc); +} + +template +constexpr void mixin_accessor() { + ElementPool elements; + mixin_layout(elements.get_ptr(), std::default_accessor()); +} + +constexpr bool test() { + mixin_accessor(); + mixin_accessor(); + mixin_accessor(); + mixin_accessor(); + mixin_accessor(); + mixin_accessor(); + return true; +} +int main(int, char**) { + (void)test(); + static_assert(test()); + return 0; +} Index: libcxx/test/std/containers/views/mdspan/mdspan/types.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/containers/views/mdspan/mdspan/types.pass.cpp @@ -0,0 +1,87 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// +// +// template> +// class mdspan { +// public: +// using extents_type = Extents; +// using layout_type = LayoutPolicy; +// using accessor_type = AccessorPolicy; +// using mapping_type = typename layout_type::template mapping; +// using element_type = ElementType; +// using value_type = remove_cv_t; +// 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 data_handle_type = typename accessor_type::data_handle_type; +// using reference = typename accessor_type::reference; +// ... +// }; + + +#include +#include +#include +#include + +#include "test_macros.h" + +#include "../MinimalElementType.h" +#include "CustomTestLayouts.h" + +template +void test_mdspan_types() { + using MDS = std::mdspan; + ASSERT_SAME_TYPE(typename MDS::extents_type, E); + ASSERT_SAME_TYPE(typename MDS::layout_type, L); + ASSERT_SAME_TYPE(typename MDS::accessor_type, A); + ASSERT_SAME_TYPE(typename MDS::mapping_type, typename L::template mapping); + ASSERT_SAME_TYPE(typename MDS::element_type, T); + ASSERT_SAME_TYPE(typename MDS::value_type, std::remove_cv_t); + ASSERT_SAME_TYPE(typename MDS::index_type, typename E::index_type); + ASSERT_SAME_TYPE(typename MDS::size_type, typename E::size_type); + ASSERT_SAME_TYPE(typename MDS::rank_type, typename E::rank_type); + ASSERT_SAME_TYPE(typename MDS::data_handle_type, typename A::data_handle_type); + ASSERT_SAME_TYPE(typename MDS::reference, typename A::reference); +} + +template +void mixin_extents() { + constexpr size_t D = std::dynamic_extent; + test_mdspan_types, L, A>(); + test_mdspan_types, L, A>(); + test_mdspan_types, L, A>(); + test_mdspan_types, L, A>(); + test_mdspan_types, L, A>(); +} + +template +void mixin_layout() { + mixin_extents(); + mixin_extents(); + mixin_extents, A>(); +} + +template +void mixin_accessor() { + mixin_layout>(); +} + +int main(int, char**) { + mixin_accessor(); + mixin_accessor(); + mixin_accessor(); + mixin_accessor(); + mixin_accessor(); + mixin_accessor(); + return 0; +}