| //===----------------------------------------------------------------------===// |
| // |
| // 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 |
| |
| // <mdspan> |
| |
| // template<class ElementType, class Extents, class LayoutPolicy = layout_right, |
| // class AccessorPolicy = default_accessor<ElementType>> |
| // class mdspan { |
| // public: |
| // 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); } |
| // |
| // constexpr size_type size() const noexcept; |
| // [[nodiscard]] constexpr bool empty() const 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); } |
| // }; |
| // |
| // Each specialization MDS of mdspan models copyable and |
| // - is_nothrow_move_constructible_v<MDS> is true, |
| // - is_nothrow_move_assignable_v<MDS> is true, and |
| // - is_nothrow_swappable_v<MDS> is true. |
| // A specialization of mdspan is a trivially copyable type if its accessor_type, mapping_type, and data_handle_type are trivially copyable types. |
| |
| #include <mdspan> |
| #include <type_traits> |
| #include <concepts> |
| #include <cassert> |
| |
| #include "test_macros.h" |
| |
| #include "../MinimalElementType.h" |
| #include "../CustomTestLayouts.h" |
| |
| template <class H, class M, class A> |
| constexpr void test_mdspan_types(const H& handle, const M& map, const A& acc) { |
| using MDS = std::mdspan<typename A::element_type, typename M::extents_type, typename M::layout_type, A>; |
| MDS m(handle, map, acc); |
| |
| // ===================================== |
| // Traits for every mdspan |
| // ===================================== |
| static_assert(std::copyable<MDS>); |
| static_assert(std::is_nothrow_move_constructible_v<MDS>); |
| static_assert(std::is_nothrow_move_assignable_v<MDS>); |
| static_assert(std::is_nothrow_swappable_v<MDS>); |
| |
| // ===================================== |
| // 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<H>) { |
| 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()); |
| 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()); |
| 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())); |
| assert(MDS::is_always_unique() == M::is_always_unique()); |
| assert(MDS::is_always_exhaustive() == M::is_always_exhaustive()); |
| 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 <class H, class L, class A> |
| 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<int>()), acc); |
| test_mdspan_types(handle, construct_mapping(layout, std::extents<signed char, D>(7)), acc); |
| test_mdspan_types(handle, construct_mapping(layout, std::extents<unsigned, 7>()), acc); |
| test_mdspan_types(handle, construct_mapping(layout, std::extents<size_t, D, 4, D>(2, 3)), acc); |
| test_mdspan_types(handle, construct_mapping(layout, std::extents<signed char, D, 7, D>(0, 3)), acc); |
| test_mdspan_types(handle, construct_mapping(layout, std::extents<int64_t, D, 7, D, 4, D, D>(1, 2, 3, 2)), acc); |
| } |
| |
| template <class H, class A> |
| 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 <class T> |
| constexpr void mixin_accessor() { |
| ElementPool<T, 1024> elements; |
| mixin_layout(elements.get_ptr(), std::default_accessor<T>()); |
| } |
| |
| constexpr bool test() { |
| mixin_accessor<int>(); |
| mixin_accessor<const int>(); |
| mixin_accessor<double>(); |
| mixin_accessor<const double>(); |
| mixin_accessor<MinimalElementType>(); |
| mixin_accessor<const MinimalElementType>(); |
| return true; |
| } |
| int main(int, char**) { |
| test(); |
| static_assert(test()); |
| return 0; |
| } |