On Wed, 16 Jul 2025, 14:48 Luc Grosheintz, <luc.groshei...@gmail.com> wrote:

> PR121061 shows that the test coverage for custom integer types is
> insufficient. Custom IndexTypes are passed to mdspan related objects in
> one of two ways:
>
>   * as a template parameter pack,
>   * or as an array/span.
>
> These two cases have different requirements on the (constness of) custom
> IndexTypes. Therefore, the tests are restructured as follows:
>
>   * allow testing with different custom integers,
>   * separate code that tests the two cases described above,
>   * use int_like.h for all tests with custom integers.
>

I like this approach, thanks.

OK for trunk.



> The affected tests are for:
>
>   * creating extents, layout_stride::mapping and mdspan from
>   custom integers,
>
>   * mapping::operator() and mdspan::operator[].
>
>         PR libstdc++/121061
>
> libstdc++-v3/ChangeLog:
>
>         * testsuite/23_containers/mdspan/extents/custom_integer.cc:
>         Enable checking with different custom integers. Improve
>         checking non-existence of overloads for incompatible custom
>         integers.
>         * testsuite/23_containers/mdspan/layouts/mapping.cc: ditto. Also
>         improve reuse of int_like.h.
>         * testsuite/23_containers/mdspan/layouts/stride.cc: ditto.
>         * testsuite/23_containers/mdspan/mdspan.cc: ditto.
>         * testsuite/23_containers/mdspan/extents/int_like.h: Rename (old
>         name).
>         * testsuite/23_containers/mdspan/int_like.h: Rename (new name).
>         (ThrowingInt): Add.
>         (NotIntLike): Add.
>
> Signed-off-by: Luc Grosheintz <luc.groshei...@gmail.com>
> ---
>  .../mdspan/extents/custom_integer.cc          |  98 +++++++-----
>  .../23_containers/mdspan/extents/int_like.h   |  30 ----
>  .../testsuite/23_containers/mdspan/int_like.h |  49 ++++++
>  .../23_containers/mdspan/layouts/mapping.cc   | 110 +++++++-------
>  .../23_containers/mdspan/layouts/stride.cc    |  20 +--
>  .../testsuite/23_containers/mdspan/mdspan.cc  | 143 ++++++++++++------
>  6 files changed, 264 insertions(+), 186 deletions(-)
>  delete mode 100644
> libstdc++-v3/testsuite/23_containers/mdspan/extents/int_like.h
>  create mode 100644 libstdc++-v3/testsuite/23_containers/mdspan/int_like.h
>
> diff --git
> a/libstdc++-v3/testsuite/23_containers/mdspan/extents/custom_integer.cc
> b/libstdc++-v3/testsuite/23_containers/mdspan/extents/custom_integer.cc
> index 404755bd5ac..4f631815b10 100644
> --- a/libstdc++-v3/testsuite/23_containers/mdspan/extents/custom_integer.cc
> +++ b/libstdc++-v3/testsuite/23_containers/mdspan/extents/custom_integer.cc
> @@ -2,7 +2,7 @@
>  #include <mdspan>
>
>  #include <testsuite_hooks.h>
> -#include "int_like.h"
> +#include "../int_like.h"
>
>  // Test construction from a custom integer-like object, that has
>  // no copy/move ctor or copy/move assignment operator.
> @@ -12,51 +12,81 @@ constexpr size_t dyn = std::dynamic_extent;
>  static_assert(std::is_convertible_v<IntLike, int>);
>  static_assert(std::is_nothrow_constructible_v<int, IntLike>);
>
> -void
> -test_shape(const auto& s2, const auto& s23)
> -{
> -  std::extents<int, 2, 3> expected;
> +template<typename Extents, bool Valid>
> +  void
> +  test_shape(const auto& shape)
> +  {
> +    static_assert(std::is_constructible_v<Extents, decltype(shape)> ==
> Valid);
>
> -  std::extents<int, 2, 3> e1(s23);
> -  VERIFY(e1 == expected);
> +    if constexpr (Valid)
> +      {
> +       std::extents<int, 2, 3> expected;
> +       Extents actual(shape);
> +       VERIFY(actual == expected);
> +      }
> +  }
>
> -  std::extents<int, dyn, 3> e2(s2);
> -  VERIFY(e2 == expected);
> +template<typename Int, bool Valid>
> +  void
> +  test_shape_all()
> +  {
> +    auto a2 = std::array<Int, 1>{Int(2)};
> +    auto s2 = std::span<Int, 1>(a2);
>
> -  std::extents<int, dyn, 3> e3(s23);
> -  VERIFY(e3 == expected);
> +    auto a23 = std::array<Int, 2>{Int(2), Int(3)};
> +    auto s23 = std::span<Int, 2>(a23);
>
> -  std::extents<int, dyn, dyn> e4(s23);
> -  VERIFY(e4 == expected);
> -}
> +    auto check = [](const auto& dyn_exts, const auto& full_exts)
> +      {
> +       test_shape<std::extents<int, 2, 3>, Valid>(full_exts);
> +       test_shape<std::extents<int, dyn, 3>, Valid>(dyn_exts);
> +       test_shape<std::extents<int, dyn, 3>, Valid>(full_exts);
> +       test_shape<std::extents<int, dyn, dyn>, Valid>(full_exts);
> +      };
>
> -void
> -test_pack()
> -{
> -  std::extents<int, 2, 3> expected;
> +    check(a2, a23);
> +    check(s2, s23);
> +  }
>
> -  std::extents<int, dyn, 3> e1(IntLike(2));
> -  VERIFY(e1 == expected);
> +// Needed because is_constructible requires that Ints are move
> constructible.
> +template<typename Extents, typename... Ints>
> +  concept has_ctor = requires
> +  {
> +    { Extents(Ints(0)...) } -> std::same_as<Extents>;
> +  };
>
> -  std::extents<int, dyn, 3> e2(IntLike(2), IntLike(3));
> -  VERIFY(e2 == expected);
> +template<typename Int, bool Valid>
> +  void
> +  test_pack_all()
> +  {
> +    static_assert(has_ctor<std::extents<int, dyn, 3>, Int> == Valid);
> +    static_assert(has_ctor<std::extents<int, dyn, 3>, Int, Int> == Valid);
> +    static_assert(has_ctor<std::extents<int, dyn, dyn>, Int, Int> ==
> Valid);
>
> -  std::extents<int, dyn, dyn> e3(IntLike(2), IntLike(3));
> -  VERIFY(e3 == expected);
> -}
> +    if constexpr (Valid)
> +      {
> +       std::extents<int, 2, 3> expected;
> +
> +       std::extents<int, dyn, 3> e1(Int(2));
> +       VERIFY(e1 == expected);
> +
> +       std::extents<int, dyn, 3> e2(Int(2), Int(3));
> +       VERIFY(e2 == expected);
> +
> +       std::extents<int, dyn, dyn> e3(Int(2), Int(3));
> +       VERIFY(e3 == expected);
> +      }
> +  }
>
>  int
>  main()
>  {
> -  auto a2 = std::array<IntLike, 1>{IntLike(2)};
> -  auto s2 = std::span<IntLike, 1>(a2);
> -
> -  auto a23 = std::array<IntLike, 2>{IntLike(2), IntLike(3)};
> -  auto s23 = std::span<IntLike, 2>(a23);
> -
> -  test_shape(a2, a23);
> -  test_shape(s2, s23);
> -  test_pack();
> +  test_shape_all<int, true>();
> +  test_shape_all<IntLike, true>();
> +  test_shape_all<ThrowingInt, false>();
>
> +  test_pack_all<int, true>();
> +  test_pack_all<IntLike, true>();
> +  test_pack_all<ThrowingInt, false>();
>    return 0;
>  }
> diff --git
> a/libstdc++-v3/testsuite/23_containers/mdspan/extents/int_like.h
> b/libstdc++-v3/testsuite/23_containers/mdspan/extents/int_like.h
> deleted file mode 100644
> index f39f4cc9081..00000000000
> --- a/libstdc++-v3/testsuite/23_containers/mdspan/extents/int_like.h
> +++ /dev/null
> @@ -1,30 +0,0 @@
> -#ifndef TEST_MDSPAN_INT_LIKE_H
> -#define TEST_MDSPAN_INT_LIKE_H
> -
> -class IntLike
> -{
> -public:
> -  explicit
> -  IntLike(int i)
> -  : _M_i(i)
> -  { }
> -
> -  IntLike() = delete;
> -  IntLike(const IntLike&) = delete;
> -  IntLike(IntLike&&) = delete;
> -
> -  const IntLike&
> -  operator=(const IntLike&) = delete;
> -
> -  const IntLike&
> -  operator=(IntLike&&) = delete;
> -
> -  constexpr
> -  operator int() const noexcept
> -  { return _M_i; }
> -
> -private:
> -  int _M_i;
> -};
> -
> -#endif // TEST_MDSPAN_INT_LIKE_H
> diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/int_like.h
> b/libstdc++-v3/testsuite/23_containers/mdspan/int_like.h
> new file mode 100644
> index 00000000000..ed45375f986
> --- /dev/null
> +++ b/libstdc++-v3/testsuite/23_containers/mdspan/int_like.h
> @@ -0,0 +1,49 @@
> +#ifndef TEST_MDSPAN_INT_LIKE_H
> +#define TEST_MDSPAN_INT_LIKE_H
> +
> +enum class CustomIndexKind
> +{
> +  Const,
> +  Throwing,
> +};
> +
> +template<CustomIndexKind Kind>
> +  class CustomIndexType
> +  {
> +  public:
> +    explicit
> +    CustomIndexType(int i)
> +    : _M_i(i)
> +    { }
> +
> +    CustomIndexType() = delete;
> +    CustomIndexType(const CustomIndexType&) = delete;
> +    CustomIndexType(CustomIndexType&&) = delete;
> +
> +    const CustomIndexType&
> +    operator=(const CustomIndexType&) = delete;
> +
> +    const CustomIndexType&
> +    operator=(CustomIndexType&&) = delete;
> +
> +    constexpr
> +    operator int() const noexcept
> +    requires (Kind == CustomIndexKind::Const)
> +    { return _M_i; }
> +
> +    constexpr
> +    operator int() const
> +    requires (Kind == CustomIndexKind::Throwing)
> +    { return _M_i; }
> +
> +  private:
> +    int _M_i;
> +  };
> +
> +using IntLike = CustomIndexType<CustomIndexKind::Const>;
> +using ThrowingInt = CustomIndexType<CustomIndexKind::Throwing>;
> +
> +struct NotIntLike
> +{ };
> +
> +#endif // TEST_MDSPAN_INT_LIKE_H
> diff --git
> a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/mapping.cc
> b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/mapping.cc
> index 963c804a369..17f0c00acf2 100644
> --- a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/mapping.cc
> +++ b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/mapping.cc
> @@ -1,6 +1,7 @@
>  // { dg-do run { target c++23 } }
>  #include <mdspan>
>
> +#include "../int_like.h"
>  #include <cstdint>
>  #include <testsuite_hooks.h>
>
> @@ -59,14 +60,13 @@ template<typename Mapping, size_t N>
>      return ret;
>    }
>
> -template<typename Mapping, typename... Indices>
> +template<typename Int, typename Mapping, typename... Indices>
>    constexpr void
>    test_linear_index(const Mapping& m, Indices... i)
>    {
>      using index_type = typename Mapping::index_type;
>      index_type expected = linear_index(m, std::array{index_type(i)...});
> -    VERIFY(m(i...) == expected);
> -    VERIFY(m(uint8_t(i)...) == expected);
> +    VERIFY(m(Int(i)...) == expected);
>    }
>
>  template<typename Layout>
> @@ -77,26 +77,26 @@ template<typename Layout>
>      VERIFY(m() == 0);
>    }
>
> -template<typename Layout>
> +template<typename Layout, typename Int>
>    constexpr void
>    test_linear_index_1d()
>    {
>      typename Layout::mapping<std::extents<int, 5>> m;
> -    test_linear_index(m, 0);
> -    test_linear_index(m, 1);
> -    test_linear_index(m, 4);
> +    test_linear_index<Int>(m, 0);
> +    test_linear_index<Int>(m, 1);
> +    test_linear_index<Int>(m, 4);
>    }
>
> -template<typename Layout>
> +template<typename Layout, typename Int>
>    constexpr void
>    test_linear_index_2d()
>    {
>      typename Layout::mapping<std::extents<int, 3, 256>> m;
> -    test_linear_index(m, 0, 0);
> -    test_linear_index(m, 1, 0);
> -    test_linear_index(m, 0, 1);
> -    test_linear_index(m, 1, 1);
> -    test_linear_index(m, 2, 4);
> +    test_linear_index<Int>(m, 0, 0);
> +    test_linear_index<Int>(m, 1, 0);
> +    test_linear_index<Int>(m, 0, 1);
> +    test_linear_index<Int>(m, 1, 1);
> +    test_linear_index<Int>(m, 2, 4);
>    }
>
>  template<typename Layout>
> @@ -141,44 +141,34 @@ template<>
>        }
>    };
>
> -template<typename Layout>
> +template<typename Layout, typename Int>
>    constexpr void
>    test_linear_index_3d()
>    {
>      auto m = MappingFactory<Layout>::create(std::extents(3, 5, 7));
> -    test_linear_index(m, 0, 0, 0);
> -    test_linear_index(m, 1, 0, 0);
> -    test_linear_index(m, 0, 1, 0);
> -    test_linear_index(m, 0, 0, 1);
> -    test_linear_index(m, 1, 1, 0);
> -    test_linear_index(m, 2, 4, 6);
> +    test_linear_index<Int>(m, 0, 0, 0);
> +    test_linear_index<Int>(m, 1, 0, 0);
> +    test_linear_index<Int>(m, 0, 1, 0);
> +    test_linear_index<Int>(m, 0, 0, 1);
> +    test_linear_index<Int>(m, 1, 1, 0);
> +    test_linear_index<Int>(m, 2, 4, 6);
>    }
>
> -struct IntLikeA
> -{
> -  operator int()
> -  { return 0; }
> -};
> -
> -struct IntLikeB
> -{
> -  operator int() noexcept
> -  { return 0; }
> -};
> -
> -struct NotIntLike
> -{ };
> +template<typename Mapping, typename... Ints>
> +  concept has_linear_index = requires (Mapping m)
> +  {
> +    { m(Ints(0)...) } -> std::same_as<typename Mapping::index_type>;
> +  };
>
>  template<typename Layout>
>    constexpr void
>    test_has_linear_index_0d()
>    {
>      using Mapping = typename Layout::mapping<std::extents<int>>;
> -    static_assert(std::invocable<Mapping>);
> -    static_assert(!std::invocable<Mapping, int>);
> -    static_assert(!std::invocable<Mapping, IntLikeA>);
> -    static_assert(!std::invocable<Mapping, IntLikeB>);
> -    static_assert(!std::invocable<Mapping, NotIntLike>);
> +    static_assert(has_linear_index<Mapping>);
> +    static_assert(!has_linear_index<Mapping, int>);
> +    static_assert(!has_linear_index<Mapping, IntLike>);
> +    static_assert(!has_linear_index<Mapping, NotIntLike>);
>    }
>
>  template<typename Layout>
> @@ -186,12 +176,13 @@ template<typename Layout>
>    test_has_linear_index_1d()
>    {
>      using Mapping = typename Layout::mapping<std::extents<int, 3>>;
> -    static_assert(std::invocable<Mapping, int>);
> -    static_assert(!std::invocable<Mapping>);
> -    static_assert(!std::invocable<Mapping, IntLikeA>);
> -    static_assert(std::invocable<Mapping, IntLikeB>);
> -    static_assert(!std::invocable<Mapping, NotIntLike>);
> -    static_assert(std::invocable<Mapping, double>);
> +    static_assert(!has_linear_index<Mapping>);
> +    static_assert(has_linear_index<Mapping, int>);
> +    static_assert(has_linear_index<Mapping, double>);
> +    static_assert(has_linear_index<Mapping, IntLike>);
> +    static_assert(!has_linear_index<Mapping, ThrowingInt>);
> +    static_assert(!has_linear_index<Mapping, NotIntLike>);
> +    static_assert(!has_linear_index<Mapping, int, int>);
>    }
>
>  template<typename Layout>
> @@ -199,22 +190,23 @@ template<typename Layout>
>    test_has_linear_index_2d()
>    {
>      using Mapping = typename Layout::mapping<std::extents<int, 3, 5>>;
> -    static_assert(std::invocable<Mapping, int, int>);
> -    static_assert(!std::invocable<Mapping, int>);
> -    static_assert(!std::invocable<Mapping, IntLikeA, int>);
> -    static_assert(std::invocable<Mapping, IntLikeB, int>);
> -    static_assert(!std::invocable<Mapping, NotIntLike, int>);
> -    static_assert(std::invocable<Mapping, double, double>);
> +    static_assert(!has_linear_index<Mapping, int>);
> +    static_assert(has_linear_index<Mapping, int, int>);
> +    static_assert(has_linear_index<Mapping, double, double>);
> +    static_assert(has_linear_index<Mapping, IntLike, int>);
> +    static_assert(!has_linear_index<Mapping, ThrowingInt, int>);
> +    static_assert(!has_linear_index<Mapping, NotIntLike, int>);
> +    static_assert(!has_linear_index<Mapping, int, int, int>);
>    }
>
> -template<typename Layout>
> +template<typename Layout, typename Int>
>    constexpr bool
>    test_linear_index_all()
>    {
>      test_linear_index_0d<Layout>();
> -    test_linear_index_1d<Layout>();
> -    test_linear_index_2d<Layout>();
> -    test_linear_index_3d<Layout>();
> +    test_linear_index_1d<Layout, Int>();
> +    test_linear_index_2d<Layout, Int>();
> +    test_linear_index_3d<Layout, Int>();
>      test_has_linear_index_0d<Layout>();
>      test_has_linear_index_1d<Layout>();
>      test_has_linear_index_2d<Layout>();
> @@ -527,7 +519,13 @@ template<typename Layout>
>    constexpr bool
>    test_mapping_all()
>    {
> -    test_linear_index_all<Layout>();
> +    test_linear_index_all<Layout, uint8_t>();
> +    test_linear_index_all<Layout, int>();
> +    if !consteval
> +      {
> +       test_linear_index_all<Layout, IntLike>();
> +      }
> +
>      test_required_span_size_all<Layout>();
>      test_stride_all<Layout>();
>
> diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/stride.cc
> b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/stride.cc
> index c8af5c61254..1267306fb5c 100644
> --- a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/stride.cc
> +++ b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/stride.cc
> @@ -1,6 +1,7 @@
>  // { dg-do run { target c++23 } }
>  #include <mdspan>
>
> +#include "../int_like.h"
>  #include <testsuite_hooks.h>
>
>  constexpr size_t dyn = std::dynamic_extent;
> @@ -42,21 +43,6 @@ test_ctor_default_stride_all()
>    return true;
>  }
>
> -struct IntLikeA
> -{
> -  operator int()
> -  { return 0; }
> -};
> -
> -struct IntLikeB
> -{
> -  operator int() noexcept
> -  { return 0; }
> -};
> -
> -struct NotIntLike
> -{ };
> -
>  template<typename E, typename E_arg, typename T, size_t N, bool Expected>
>  constexpr void
>  test_stride_constructible()
> @@ -77,8 +63,8 @@ test_stride_constructible_all()
>    using E2 = std::extents<int, dyn>;
>
>    test_stride_constructible<E0, E0, int, 0, true>();
> -  test_stride_constructible<E0, E0, IntLikeA, 0, false>();
> -  test_stride_constructible<E0, E0, IntLikeB, 0, true>();
> +  test_stride_constructible<E0, E0, IntLike, 0, true>();
> +  test_stride_constructible<E0, E0, ThrowingInt, 0, false>();
>    test_stride_constructible<E0, E0, NotIntLike, 0, false>();
>    test_stride_constructible<E1, E1, int, 1, true>();
>    test_stride_constructible<E2, E1, int, 1, true>();
> diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/mdspan.cc
> b/libstdc++-v3/testsuite/23_containers/mdspan/mdspan.cc
> index a650fb19bdf..adabb0c6639 100644
> --- a/libstdc++-v3/testsuite/23_containers/mdspan/mdspan.cc
> +++ b/libstdc++-v3/testsuite/23_containers/mdspan/mdspan.cc
> @@ -2,7 +2,7 @@
>  #include <mdspan>
>
>  #include <testsuite_hooks.h>
> -#include "extents/int_like.h"
> +#include "int_like.h"
>  #include "layout_like.h"
>
>  constexpr auto dyn = std::dynamic_extent;
> @@ -317,32 +317,50 @@ test_from_accessor()
>    return true;
>  }
>
> -void
> -test_from_int_like()
> -{
> -  constexpr size_t n = 3*5*7;
> -  std::array<double, n> storage{};
> +template<typename MDSpan, typename Pointer, typename... Ints>
> +  concept has_pack_ctor = requires
> +  {
> +    { MDSpan(Pointer{}, Ints(0)...) } -> std::same_as<MDSpan>;
> +  };
>
> -  auto verify = [&](auto md)
> -    {
> -      VERIFY(md.data_handle() == storage.data());
> -      VERIFY(md.extent(0) == 3);
> -      VERIFY(md.extent(1) == 5);
> -      VERIFY(md.extent(2) == 7);
> +template<typename CustomInt, bool ValidForPacks, bool ValidForArrays>
> +  constexpr bool
> +  test_from_int_like()
> +  {
> +    constexpr size_t n = 3*5*7;
> +    std::array<double, n> storage{};
>
> -      VERIFY((md[IntLike(0), 0, IntLike(0)]) == 0.0);
> -      auto zero = std::array{IntLike(0), IntLike(0), IntLike(0)};
> -      auto zero_view = std::span<IntLike, 3>{zero};
> -      VERIFY((md[zero]) == 0.0);
> -      VERIFY((md[zero_view]) == 0.0);
> -    };
> +    auto verify = [&](auto md)
> +      {
> +       VERIFY(md.data_handle() == storage.data());
> +       VERIFY(md.extent(0) == 3);
> +       VERIFY(md.extent(1) == 5);
> +       VERIFY(md.extent(2) == 7);
> +      };
>
> -  auto shape = std::array{IntLike(3), IntLike(5), IntLike(7)};
> -  auto shape_view = std::span<IntLike, 3>{shape};
> -  verify(std::mdspan(storage.data(), IntLike(3), 5, IntLike(7)));
> -  verify(std::mdspan(storage.data(), shape));
> -  verify(std::mdspan(storage.data(), shape_view));
> -}
> +    static_assert(has_pack_ctor<std::mdspan<float, std::dextents<int, 3>>,
> +       float*, CustomInt, int, CustomInt> == ValidForPacks);
> +
> +    static_assert(std::is_constructible_v<
> +       std::mdspan<float, std::dextents<int, 3>>, float*,
> +       std::span<CustomInt, 3>> == ValidForArrays);
> +
> +    static_assert(std::is_constructible_v<
> +       std::mdspan<float, std::dextents<int, 3>>, float*,
> +       std::array<CustomInt, 3>> == ValidForArrays);
> +
> +    if constexpr (ValidForPacks)
> +      verify(std::mdspan(storage.data(), CustomInt(3), 5, CustomInt(7)));
> +
> +    if constexpr (ValidForArrays)
> +      {
> +       auto shape = std::array{CustomInt(3), CustomInt(5), CustomInt(7)};
> +       auto shape_view = std::span<CustomInt, 3>{shape};
> +       verify(std::mdspan(storage.data(), shape));
> +       verify(std::mdspan(storage.data(), shape_view));
> +      }
> +    return true;
> +  }
>
>  template<typename T, bool NothrowConstructible = true,
>          bool NothrowAssignable = true>
> @@ -491,32 +509,53 @@ test_empty_all()
>    return true;
>  }
>
> -constexpr bool
> -test_access()
> +template<typename MDSpan, typename... Args>
> +concept indexable = requires (MDSpan md, Args... args)
>  {
> -  using Extents = std::extents<int, 3, 5, 7>;
> -  auto exts = Extents{};
> +  { md[args...] } -> std::same_as<typename MDSpan::reference>;
> +};
>
> -  auto mapping = std::layout_left::mapping(exts);
> -  constexpr size_t n = mapping.required_span_size();
> -  std::array<double, n> storage{};
> +template<typename Int, bool ValidForPacks, bool ValidForArrays>
> +  constexpr bool
> +  test_access()
> +  {
> +    using Extents = std::extents<int, 3, 5, 7>;
> +    auto exts = Extents{};
>
> -  auto md = std::mdspan(storage.data(), mapping);
> -  static_assert(std::__mdspan::__mapping_alike<decltype(md)>);
> +    auto mapping = std::layout_left::mapping(exts);
> +    constexpr size_t n = mapping.required_span_size();
> +    std::array<double, n> storage{};
>
> -  for(int i = 0; i < exts.extent(0); ++i)
> -    for(int j = 0; j < exts.extent(1); ++j)
> -      for(int k = 0; k < exts.extent(2); ++k)
> -       {
> -         std::array<int, 3> ijk{i, j, k};
> -         storage[mapping(i, j, k)] = 1.0;
> -         VERIFY((md[i, j, k]) == 1.0);
> -         VERIFY((md[ijk]) == 1.0);
> -         VERIFY((md[std::span(ijk)]) == 1.0);
> -         storage[mapping(i, j, k)] = 0.0;
> -       }
> -  return true;
> -}
> +    auto md = std::mdspan(storage.data(), mapping);
> +    using MDSpan = decltype(md);
> +
> +    for(int i = 0; i < exts.extent(0); ++i)
> +      for(int j = 0; j < exts.extent(1); ++j)
> +       for(int k = 0; k < exts.extent(2); ++k)
> +         {
> +           storage[mapping(i, j, k)] = 1.0;
> +           if constexpr (ValidForPacks)
> +             VERIFY((md[Int(i), Int(j), Int(k)]) == 1.0);
> +
> +           if constexpr (ValidForArrays)
> +             {
> +               std::array<Int, 3> ijk{Int(i), Int(j), Int(k)};
> +               VERIFY((md[ijk]) == 1.0);
> +               VERIFY((md[std::span(ijk)]) == 1.0);
> +             }
> +           storage[mapping(i, j, k)] = 0.0;
> +         }
> +
> +    if constexpr (!ValidForPacks)
> +      static_assert(!indexable<MDSpan, Int, int, Int>);
> +
> +    if constexpr (!ValidForArrays)
> +      {
> +       static_assert(!indexable<MDSpan, std::array<Int, 3>>);
> +       static_assert(!indexable<MDSpan, std::span<Int, 3>>);
> +      }
> +    return true;
> +  }
>
>  constexpr bool
>  test_swap()
> @@ -650,14 +689,20 @@ main()
>    test_from_accessor();
>    static_assert(test_from_accessor());
>
> -  test_from_int_like();
> +  test_from_int_like<int, true, true>();
> +  static_assert(test_from_int_like<int, true, true>());
> +  test_from_int_like<IntLike, true, true>();
> +  test_from_int_like<ThrowingInt, false, false>();
> +
>    test_from_opaque_accessor();
>    test_from_base_class_accessor();
>    test_from_mapping_like();
>    static_assert(test_from_mapping_like());
>
> -  test_access();
> -  static_assert(test_access());
> +  test_access<int, true, true>();
> +  static_assert(test_access<int, true, true>());
> +  test_access<IntLike, true, true>();
> +  test_access<ThrowingInt, false, false>();
>
>    test_swap();
>    static_assert(test_swap());
> --
> 2.50.0
>
>

Reply via email to