Also LGTM, thanks for moving int_like.h to mdspan.
Just pushed it to master.

On Wed, Jul 16, 2025 at 10:04 PM Jonathan Wakely <jwakely....@gmail.com>
wrote:

>
>
> 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