On Tue, Apr 15, 2025 at 10:55 AM Luc Grosheintz <luc.groshei...@gmail.com>
wrote:

> A prior commit added std::extents, this commit adds the tests. The bulk
> is focussed on testing the constructors. These are split into three
> groups:
>
> 1. the ctor from other extents and the copy ctor,
> 2. the ctor from a pack of integer-like objects,
> 3. the ctor from shapes, i.e. span and array.
>
> For each group check that the ctor:
> * produces an object with the expected values for extent,
> * is implicit if and only if required,
> * is constexpr,
> * doesn't change the rank of the extent.
>
> libstdc++-v3/ChangeLog:
>
>         * testsuite/23_containers/mdspan/extents/assign.cc: New test.
>         * testsuite/23_containers/mdspan/extents/class_properties.cc: New
> test.
>         * testsuite/23_containers/mdspan/extents/ctor_copy.cc: New test.
>         * testsuite/23_containers/mdspan/extents/ctor_copy_constexpr.cc:
> New test.
>         * testsuite/23_containers/mdspan/extents/ctor_ints.cc: New test.
>         * testsuite/23_containers/mdspan/extents/ctor_ints_constexpr.cc:
> New test.
>         *
> testsuite/23_containers/mdspan/extents/ctor_shape_all_extents.cc: New test.
>         * testsuite/23_containers/mdspan/extents/ctor_shape_constexpr.cc:
> New test.
>         *
> testsuite/23_containers/mdspan/extents/ctor_shape_dynamic_extents.cc: New
> test.
>         * testsuite/23_containers/mdspan/extents/custom_integer.cc: New
> test.
>         * testsuite/23_containers/mdspan/extents/deduction_guide.cc: New
> test.
>         * testsuite/23_containers/mdspan/extents/dextents.cc: New test.
>         * testsuite/23_containers/mdspan/extents/extent.cc: New test.
>         * testsuite/23_containers/mdspan/extents/ops_eq.cc: New test.
>
The DejaGnu configuration that we use for testing, has some overhead
(another file is compiled)
per each separate test file, so I would suggest merging some of these test
cases.

>
> Signed-off-by: Luc Grosheintz <luc.groshei...@gmail.com>
> ---
>  .../23_containers/mdspan/extents/assign.cc    | 29 ++++++
>  .../mdspan/extents/class_properties.cc        | 62 +++++++++++++
>  .../23_containers/mdspan/extents/ctor_copy.cc | 75 +++++++++++++++
>  .../mdspan/extents/ctor_copy_constexpr.cc     | 20 ++++
>  .../23_containers/mdspan/extents/ctor_ints.cc | 58 ++++++++++++
>  .../mdspan/extents/ctor_ints_constexpr.cc     | 12 +++
>  .../mdspan/extents/ctor_shape_all_extents.cc  | 61 +++++++++++++
>  .../mdspan/extents/ctor_shape_constexpr.cc    | 23 +++++
>  .../extents/ctor_shape_dynamic_extents.cc     | 91 +++++++++++++++++++
>  .../mdspan/extents/custom_integer.cc          | 87 ++++++++++++++++++
>  .../mdspan/extents/deduction_guide.cc         | 34 +++++++
>  .../23_containers/mdspan/extents/dextents.cc  | 11 +++
>  .../23_containers/mdspan/extents/extent.cc    | 24 +++++
>  .../23_containers/mdspan/extents/ops_eq.cc    | 58 ++++++++++++
>  14 files changed, 645 insertions(+)
>  create mode 100644
> libstdc++-v3/testsuite/23_containers/mdspan/extents/assign.cc
>  create mode 100644
> libstdc++-v3/testsuite/23_containers/mdspan/extents/class_properties.cc
>  create mode 100644
> libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_copy.cc
>  create mode 100644
> libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_copy_constexpr.cc
>  create mode 100644
> libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_ints.cc
>  create mode 100644
> libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_ints_constexpr.cc
>  create mode 100644
> libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_shape_all_extents.cc
>  create mode 100644
> libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_shape_constexpr.cc
>  create mode 100644
> libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_shape_dynamic_extents.cc
>  create mode 100644
> libstdc++-v3/testsuite/23_containers/mdspan/extents/custom_integer.cc
>  create mode 100644
> libstdc++-v3/testsuite/23_containers/mdspan/extents/deduction_guide.cc
>  create mode 100644
> libstdc++-v3/testsuite/23_containers/mdspan/extents/dextents.cc
>  create mode 100644
> libstdc++-v3/testsuite/23_containers/mdspan/extents/extent.cc
>  create mode 100644
> libstdc++-v3/testsuite/23_containers/mdspan/extents/ops_eq.cc
>
> diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/extents/assign.cc
> b/libstdc++-v3/testsuite/23_containers/mdspan/extents/assign.cc
> new file mode 100644
> index 00000000000..3bc32361a7b
> --- /dev/null
> +++ b/libstdc++-v3/testsuite/23_containers/mdspan/extents/assign.cc
> @@ -0,0 +1,29 @@
> +// { dg-do run { target c++23 } }
> +#include <mdspan>
> +
> +#include <testsuite_hooks.h>
> +
> +constexpr auto dyn = std::dynamic_extent;
> +
> +static_assert(std::is_nothrow_assignable_v<std::extents<int, dyn, 2>,
> +                                          std::extents<int, 1, 2>>);
> +
> +int
> +main()
> +{
> +  auto e1 = std::extents<int, 1, 2>();
> +  auto e2 = std::extents<int, 1, 2>();
> +
> +  e2 = e1;
> +  VERIFY(e2 == e1);
> +
> +  auto e5 = std::extents<int, 1, dyn>();
> +  e5 = e1;
> +  VERIFY(e5 == e1);
> +
> +  auto e3 = std::extents<int, dyn, dyn>(1, 2);
> +  auto e4 = std::extents<int, dyn, dyn>(3, 4);
> +  e3 = e4;
> +  VERIFY(e3 == e4);
> +  return 0;
> +}
> diff --git
> a/libstdc++-v3/testsuite/23_containers/mdspan/extents/class_properties.cc
> b/libstdc++-v3/testsuite/23_containers/mdspan/extents/class_properties.cc
> new file mode 100644
> index 00000000000..548900a7f44
> --- /dev/null
> +++
> b/libstdc++-v3/testsuite/23_containers/mdspan/extents/class_properties.cc
> @@ -0,0 +1,62 @@
> +// { dg-do compile { target c++23 } }
> +#include <mdspan>
> +
> +#include <type_traits>
> +
> +constexpr auto dyn = std::dynamic_extent;
> +
> +// Check class traits.
> +static_assert(std::regular<std::extents<int>>);
> +static_assert(std::regular<std::extents<int, 1>>);
> +static_assert(std::regular<std::extents<int, dyn>>);
> +
> +static_assert(std::is_trivially_copyable_v<std::extents<int>>);
> +static_assert(std::is_trivially_copyable_v<std::extents<int, 1>>);
> +static_assert(std::is_trivially_copyable_v<std::extents<int, dyn>>);
> +
> +// Check member typedefs.
> +static_assert(std::is_same_v<std::extents<int, 1, 2>::rank_type, size_t>);
> +
> +static_assert(std::is_unsigned_v<std::extents<int, 2>::size_type>);
> +static_assert(std::is_unsigned_v<std::extents<unsigned int,
> 2>::size_type>);
> +
> +static_assert(std::is_same_v<std::extents<char, 2>::index_type, char>);
> +static_assert(std::is_same_v<std::extents<int, 2>::index_type, int>);
> +static_assert(std::is_same_v<std::extents<unsigned int, 2>::index_type,
> +             unsigned int>);
> +
> +// Check `rank`.
> +static_assert(std::extents<int, 1>::rank() == 1);
> +static_assert(std::extents<int, dyn>::rank() == 1);
> +static_assert(std::extents<int, 2, dyn>::rank() == 2);
> +
> +// Check `rank_dynamic`.
> +static_assert(std::extents<int, 1>::rank_dynamic() == 0);
> +static_assert(std::extents<int, dyn>::rank_dynamic() == 1);
> +static_assert(std::extents<int, 2, dyn>::rank_dynamic() == 1);
> +static_assert(std::extents<int, dyn, dyn>::rank_dynamic() == 2);
> +
> +template<class T, size_t... Extents>
> +  constexpr bool
> +  check_rank_return_types()
> +  {
> +    auto e = std::extents<T, Extents...>();
> +    return std::is_same_v<decltype(e.rank()), size_t>
> +          && std::is_same_v<decltype(e.rank_dynamic()), size_t>;
> +  }
> +
> +static_assert(check_rank_return_types<int, 1>());
> +
> +// Check that the static extents don't take up space.
> +static_assert(sizeof(std::extents<int, 1, dyn>) == sizeof(int));
> +static_assert(sizeof(std::extents<char, 1, dyn>) == sizeof(char));
> +
> +template<typename Extents>
> +class Container
> +{
> +  int dummy;
> +  [[no_unique_address]] std::extents<size_t> b0;
> +};
> +
> +static_assert(sizeof(Container<std::extents<char, 1, 2>>) == sizeof(int));
> +static_assert(sizeof(Container<std::extents<size_t, 1, 2>>) ==
> sizeof(int));
> diff --git
> a/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_copy.cc
> b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_copy.cc
> new file mode 100644
> index 00000000000..44eeab2ef22
> --- /dev/null
> +++ b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_copy.cc
> @@ -0,0 +1,75 @@
> +// { dg-do run { target c++23 } }
> +#include <mdspan>
> +
> +#include <testsuite_hooks.h>
> +#include <type_traits>
> +
> +// Test the copy ctor and the ctor from other extents.
> +
> +constexpr auto dyn = std::dynamic_extent;
> +
> +// Not constructible
> +static_assert(!std::is_constructible_v<std::extents<int>,
> +                                      std::extents<int, 1>>);
> +
> +static_assert(!std::is_constructible_v<std::extents<int, 1, 1>,
> +                                      std::extents<int, 1>>);
> +
> +static_assert(!std::is_constructible_v<std::extents<int, dyn>,
> +                                      std::extents<int, dyn, dyn>>);
> +
> +static_assert(!std::is_constructible_v<std::extents<int, 2, 2>,
> +                                      std::extents<int, 1, 2>>);
> +
> +// Nothrow constructible
> +static_assert(std::is_nothrow_constructible_v<std::extents<int, 1>,
> +                                             std::extents<unsigned int,
> dyn>>);
> +static_assert(std::is_nothrow_constructible_v<std::extents<unsigned int,
> dyn>,
> +                                             std::extents<int, 1>>);
> +
> +// Implicit conversion
> +static_assert(!std::is_convertible_v<std::extents<unsigned int>,
> +                                    std::extents<int>>);
> +static_assert(std::is_convertible_v<std::extents<int>,
> +                                   std::extents<unsigned int>>);
> +
> +static_assert(!std::is_convertible_v<std::extents<unsigned int, 1>,
> +                                    std::extents<int, 1>>);
> +static_assert(std::is_convertible_v<std::extents<int, 1>,
> +                                   std::extents<unsigned int, 1>>);
> +
> +static_assert(!std::is_convertible_v<std::extents<int, dyn>,
> +                                    std::extents<int, 1>>);
> +static_assert(std::is_convertible_v<std::extents<int, 1>,
> +                                   std::extents<int, dyn>>);
> +
> +static_assert(!std::is_convertible_v<std::extents<unsigned int, 1>,
> +                                    std::extents<int, dyn>>);
> +static_assert(std::is_convertible_v<std::extents<int, 1>,
> +                                   std::extents<unsigned int, dyn>>);
> +
> +template<class T, size_t ... Extents, class Other>
> +  void
> +  test_ctor(const Other& other)
> +  {
> +    auto e = std::extents<T, Extents...>(other);
> +    VERIFY(e == other);
> +  }
> +
> +int
> +main()
> +{
> +  auto e0 = std::extents<int>();
> +  test_ctor<int>(e0);
> +
> +  auto e1 = std::extents<int, 1, 2, 3>();
> +  test_ctor<int, 1, 2, 3>(e1);
> +  test_ctor<int, 1, dyn, 3>(e1);
> +  test_ctor<unsigned int, 1, dyn, 3>(e1);
> +
> +  auto e2 = std::extents<unsigned int, 1, dyn, 3>{1, 2, 3};
> +  test_ctor<int, 1, 2, 3>(e2);
> +  test_ctor<int, 1, dyn, 3>(e2);
> +  test_ctor<int, 1, dyn, dyn>(e2);
> +  return 0;
> +}
> diff --git
> a/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_copy_constexpr.cc
> b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_copy_constexpr.cc
> new file mode 100644
> index 00000000000..49fa023c354
> --- /dev/null
> +++
> b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_copy_constexpr.cc
> @@ -0,0 +1,20 @@
> +// { dg-do compile { target c++23 } }
> +#include <mdspan>
> +
> +// Test that the ctor from other extents is constexpr.
>
The trick that is commonly used here is to write the constructor as
constexpr function returning bool:
template<class T, size_t ... Extents, class Other>
  constexpr void
  test_ctor(const Other& other)
  {
    auto e = std::extents<T, Extents...>(other);
    VERIFY(e == other);
  }

constexpr bool
test_ctors()
{
  auto e0 = std::extents<int>();
  test_ctor<int>(e0);
  // ....

  return true;
}

And in the main, you can both verify runtime and compile-time code, by
invoking:
int main()
{
  test_ctors();
  static_assert( test_ctors() );
}
I would suggest reworking files in that manner.
+
+int
+main()
+{
+  auto e0 = std::extents<int>();
+  test_ctor<int>(e0);
+
+  auto e1 = std::extents<int, 1, 2, 3>();
+  test_ctor<int, 1, 2, 3>(e1);
+  test_ctor<int, 1, dyn, 3>(e1);
+  test_ctor<unsigned int, 1, dyn, 3>(e1);

> +
> +constexpr auto dyn = std::dynamic_extent;
> +
> +constexpr std::extents<int> e0;
> +constexpr std::extents<int> e1 = e0;
> +
> +constexpr std::extents<int, 1> e2;
> +constexpr std::extents<int, 1> e3 = e2;
> +static_assert(e3 == e2);
> +
> +constexpr std::extents<int, dyn> e4 = e2;
> +static_assert(e4 == e2);
> +
> +constexpr std::extents<int, 3, 5> e5;
> +constexpr std::extents<int, dyn, 5> e6 = e5;
> +static_assert(e6 == e5);
> diff --git
> a/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_ints.cc
> b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_ints.cc
> new file mode 100644
> index 00000000000..3b23787ca15
> --- /dev/null
> +++ b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_ints.cc
> @@ -0,0 +1,58 @@
> +// { dg-do run { target c++23 } }
> +#include <mdspan>
> +
> +#include <testsuite_hooks.h>
> +
> +constexpr auto dyn = std::dynamic_extent;
> +
> +template<class Lhs, class Rhs>
> +  void
> +  verify(const Lhs& lhs, const Rhs& rhs)
> +  { VERIFY(lhs == rhs); }
> +
> +class A {};
> +
> +// Not constructible if the number of integer-like arguments isn't either
> +// rank() or rank_dynamic().
> +static_assert(!std::is_constructible_v<std::extents<int>, int>);
> +static_assert(!std::is_constructible_v<std::extents<int, dyn, dyn>, int>);
> +static_assert(!std::is_constructible_v<std::extents<int, 1, dyn, 3>, int,
> int>);
> +
> +// Not constructible from non integer-like objects.
> +static_assert(!std::is_constructible_v<std::extents<int, 1>, int, A>);
> +
> +// No implicit conversion from integer-like objects.
> +template<typename Extent, typename... OExtents>
> +  constexpr bool
> +  is_explicit()
> +  {
> +    return std::is_nothrow_constructible_v<Extent, OExtents...>
> +          && !std::is_convertible_v<Extent, OExtents...>;
> +  }
> +
> +static_assert(is_explicit<std::extents<int, 1>, int>());
> +static_assert(is_explicit<std::extents<int, 1>, unsigned int>());
> +static_assert(is_explicit<std::extents<unsigned int, 1>, int>());
> +
> +int
> +main()
> +{
> +  auto expected = std::extents<int, 1, 2, 3>(1, 2, 3);
> +
> +  // From all extents.
> +  verify(std::extents<int, 1, 2, 3>(1, 2, 3), expected);
> +  verify(std::extents<int, dyn, 2, 3>(1, 2, 3), expected);
> +  verify(std::extents<int, dyn, 2, dyn>(1, 2, 3), expected);
> +
> +  verify(std::extents<int, 1, 2, 3>{1, 2, 3}, expected);
> +  verify(std::extents<int, dyn, 2, 3>{1, 2, 3}, expected);
> +  verify(std::extents<int, dyn, 2, dyn>{1, 2, 3}, expected);
> +
> +  // From only dynamic extents.
> +  verify(std::extents<int, dyn, 2, 3>(1), expected);
> +  verify(std::extents<int, dyn, 2, dyn>(1, 3), expected);
> +
> +  verify(std::extents<int, dyn, 2, 3>{1}, expected);
> +  verify(std::extents<int, dyn, 2, dyn>{1, 3}, expected);
> +  return 0;
> +}
> diff --git
> a/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_ints_constexpr.cc
> b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_ints_constexpr.cc
> new file mode 100644
> index 00000000000..11f1520c652
> --- /dev/null
> +++
> b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_ints_constexpr.cc
> @@ -0,0 +1,12 @@
> +// { dg-do compile { target c++23 } }
> +#include <mdspan>
> +
> +constexpr auto dyn = std::dynamic_extent;
> +
> +constexpr auto e0 = std::extents<int, 1, 2>(1, 2);
> +constexpr auto e1 = std::extents<int, 1, dyn>(2);
> +constexpr auto e3 = std::extents<int, dyn, dyn>(1, 2);
> +
> +constexpr auto e4 = std::extents<int, 1, 2>{1, 2};
> +constexpr auto e5 = std::extents<int, 1, dyn>{2};
> +constexpr auto e6 = std::extents<int, dyn, dyn>{1, 2};
> diff --git
> a/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_shape_all_extents.cc
> b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_shape_all_extents.cc
> new file mode 100644
> index 00000000000..78d2b22bb40
> --- /dev/null
> +++
> b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_shape_all_extents.cc
> @@ -0,0 +1,61 @@
> +// { dg-do run { target c++23 } }
> +#include <mdspan>
> +
> +#include <testsuite_hooks.h>
> +
> +constexpr auto dyn = std::dynamic_extent;
> +
> +static_assert(std::is_nothrow_constructible_v<std::extents<int, 1, 2>,
> +                                             std::array<int, 2>>);
> +static_assert(std::is_nothrow_constructible_v<std::extents<int, 1, 2>,
> +                                             std::span<int, 2>>);
> +
> +// Not constructibe if the size of the shape isn't rank() or
> rank_dynamic().
> +static_assert(!std::is_constructible_v<std::extents<int, 1, 2>,
> +                                      std::array<int, 1>>);
> +static_assert(!std::is_constructible_v<std::extents<int, dyn, dyn>,
> +                                      std::array<int, 1>>);
> +
> +template<typename Lhs, typename Rhs>
> +  void
> +  verify(const Lhs& lhs, const Rhs& rhs)
> +  { VERIFY(lhs == rhs); }
> +
> +void
> +test_common_shapes()
> +{
> +  auto array = std::array<int, 3>{1, 2, 3};
> +  auto span_const = std::span<const int, 3>(array);
> +  auto span = std::span<int, 3>(array);
> +
> +  auto check = [](auto shape)
> +  {
> +    auto expected = std::extents<int, 1, 2, 3>();
> +    verify(std::extents<int, 1, dyn, 3>(shape), expected);
> +    verify(std::extents<int, dyn, dyn, dyn>(shape), expected);
> +    verify(std::extents<int, 1, 2, 3>(shape), expected);
> +  };
> +
> +  check(array);
> +  check(span);
> +  check(span_const);
> +}
> +
> +void
> +test_empty_shapes()
> +{
> +  auto shape = std::array<int, 0>();
> +  auto span = std::span<int, 0>(shape);
> +
> +  auto expected = std::extents<int>();
> +  verify(std::extents<int>(shape), expected);
> +  verify(std::extents<int>(span), expected);
> +}
> +
> +int
> +main()
> +{
> +  test_common_shapes();
> +  test_empty_shapes();
> +  return 0;
> +}
> diff --git
> a/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_shape_constexpr.cc
> b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_shape_constexpr.cc
> new file mode 100644
> index 00000000000..8abe069c8c6
> --- /dev/null
> +++
> b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_shape_constexpr.cc
> @@ -0,0 +1,23 @@
> +// { dg-do compile { target c++23 } }
> +#include <mdspan>
> +
> +constexpr auto dyn = std::dynamic_extent;
> +
> +constexpr auto a0 = std::array<int, 0>{};
> +constexpr auto a1 = std::array<int, 1>{2};
> +constexpr auto a2 = std::array<int, 2>{1, 2};
> +
> +constexpr auto e0 = std::extents<int, 1, 2>(a0);
> +constexpr auto e1 = std::extents<int, 1, dyn>(a1);
> +constexpr auto e2 = std::extents<int, 1, 2>(a2);
> +constexpr auto e3 = std::extents<int, dyn, dyn>(a2);
> +
> +constexpr auto s0 = std::span<const int, 0>(a0);
> +constexpr auto s1 = std::span<const int, 1>(a1);
> +constexpr auto s2 = std::span<const int, 2>(a2);
> +
> +constexpr auto e4 = std::extents<int, 1, 2>(s0);
> +constexpr auto e5 = std::extents<int, 1, dyn>(s1);
> +constexpr auto e6 = std::extents<int, 1, 2>(s2);
> +constexpr auto e7 = std::extents<int, dyn, dyn>(s2);
> +
> diff --git
> a/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_shape_dynamic_extents.cc
> b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_shape_dynamic_extents.cc
> new file mode 100644
> index 00000000000..f02f21bbb25
> --- /dev/null
> +++
> b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_shape_dynamic_extents.cc
> @@ -0,0 +1,91 @@
> +// { dg-do run { target c++23 } }
> +#include <mdspan>
> +
> +#include <testsuite_hooks.h>
> +
> +constexpr size_t dyn = std::dynamic_extent;
> +
> +template<typename Extent, typename T, size_t N>
> +  constexpr bool
> +  constructible()
> +  {
> +    return std::is_nothrow_constructible_v<Extent, std::array<T, N>>
> +          && std::is_nothrow_constructible_v<Extent, std::span<T, N>>;
> +  }
> +
> +template<typename Extent, typename T, size_t N>
> +  constexpr bool
> +  convertible()
> +  {
> +    return std::is_convertible_v<std::array<T, N>, Extent>
> +          && std::is_convertible_v<std::span<T, N>, Extent>;
> +  }
> +
> +template<typename Extent, typename T, size_t N>
> +  constexpr bool
> +  not_convertible()
> +  {
> +    return !std::is_convertible_v<std::array<T, N>, Extent>
> +          && !std::is_convertible_v<std::span<T, N>, Extent>;
> +  }
> +
> +static_assert(constructible<std::extents<int>, int, 0>());
> +static_assert(convertible<std::extents<int>, int, 0>());
> +static_assert(convertible<std::extents<unsigned int>, int, 0>());
> +static_assert(convertible<std::extents<int>, unsigned int, 0>());
> +
> +static_assert(constructible<std::extents<int, 1, dyn>, int, 1>());
> +static_assert(convertible<std::extents<int, 1, dyn>, int, 1>());
> +static_assert(convertible<std::extents<unsigned int, 1, dyn>, int, 1>());
> +static_assert(convertible<std::extents<int, 1, dyn>, unsigned int, 1>());
> +
> +static_assert(constructible<std::extents<int, 1, dyn>, int, 2>());
> +static_assert(not_convertible<std::extents<int, 1, dyn>, int, 2>());
> +static_assert(not_convertible<std::extents<unsigned int, 1, dyn>, int,
> 2>());
> +static_assert(not_convertible<std::extents<int, 1, dyn>, unsigned int,
> 2>());
> +
> +// Non-integer, but convertible.
> +static_assert(constructible<std::extents<int, dyn>, double, 1>());
> +static_assert(convertible<std::extents<int, dyn>, double, 1>());
> +
> +template<typename Extents, typename Shape>
> +  void
> +  test_ctor(const Shape& shape)
> +  {
> +    Extents e = shape;
> +
> +    VERIFY(e.rank_dynamic() == shape.size());
> +
> +    size_t di = 0;
> +    for(size_t i = 0; i < e.rank(); ++i)
> +      if(e.static_extent(i) == dyn)
> +       VERIFY(e.extent(i) == shape[di++]);
> +  }
> +
> +template<typename Extents, typename T, size_t N>
> +  void
> +  test_all_shape_types(std::array<T, N> shape)
> +  {
> +    test_ctor<Extents>(shape);
> +    test_ctor<Extents>(std::span<T, N>(shape));
> +    test_ctor<Extents>(std::span<const T, N>(shape));
> +  }
> +
> +void
> +test_common_shapes()
> +{
> +  auto s = std::array<int, 0>{};
> +  auto s2 = std::array<int, 1>{2};
> +  auto s123 = std::array<int, 3>{1, 2, 3};
> +
> +  test_all_shape_types<std::extents<int, 1, dyn, 3>>(s2);
> +  test_all_shape_types<std::extents<int, dyn, dyn, dyn>>(s123);
> +  test_all_shape_types<std::extents<int, 1, 2, 3>>(s);
> +}
> +
> +int
> +main()
> +{
> +  test_common_shapes();
> +  return 0;
> +}
> diff --git
> a/libstdc++-v3/testsuite/23_containers/mdspan/extents/custom_integer.cc
> b/libstdc++-v3/testsuite/23_containers/mdspan/extents/custom_integer.cc
> new file mode 100644
> index 00000000000..2907ad12ae7
> --- /dev/null
> +++ b/libstdc++-v3/testsuite/23_containers/mdspan/extents/custom_integer.cc
> @@ -0,0 +1,87 @@
> +// { dg-do run { target c++23 } }
> +#include <mdspan>
> +
> +#include <testsuite_hooks.h>
> +
> +// Test construction from a custom integer-like object, that has
> +// no copy/move ctor or copy/move assignment operator.
> +
> +constexpr size_t dyn = std::dynamic_extent;
> +
> +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;
> +};
> +
> +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;
> +
> +  std::extents<int, 2, 3> e1(s23);
> +  VERIFY(e1 == expected);
> +
> +  std::extents<int, dyn, 3> e2(s2);
> +  VERIFY(e2 == expected);
> +
> +  std::extents<int, dyn, 3> e3(s23);
> +  VERIFY(e3 == expected);
> +
> +  std::extents<int, dyn, dyn> e4(s23);
> +  VERIFY(e4 == expected);
> +}
> +
> +void
> +test_pack()
> +{
> +  std::extents<int, 2, 3> expected;
> +
> +  std::extents<int, dyn, 3> e1(IntLike(2));
> +  VERIFY(e1 == expected);
> +
> +  std::extents<int, dyn, 3> e2(IntLike(2), IntLike(3));
> +  VERIFY(e2 == expected);
> +
> +  std::extents<int, dyn, dyn> e3(IntLike(2), IntLike(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();
> +
> +  return 0;
> +}
> diff --git
> a/libstdc++-v3/testsuite/23_containers/mdspan/extents/deduction_guide.cc
> b/libstdc++-v3/testsuite/23_containers/mdspan/extents/deduction_guide.cc
> new file mode 100644
> index 00000000000..974fa48febd
> --- /dev/null
> +++
> b/libstdc++-v3/testsuite/23_containers/mdspan/extents/deduction_guide.cc
> @@ -0,0 +1,34 @@
> +// { dg-do compile { target c++23 } }
> +#include <mdspan>
> +
> +#include <type_traits>
> +
> +constexpr auto dyn = std::dynamic_extent;
> +
> +constexpr auto e0 = std::extents();
> +static_assert(std::is_same_v<decltype(e0), const std::dextents<size_t,
> 0>>);
> +static_assert(e0 == std::extents<size_t>());
> +
> +constexpr auto e1 = std::extents(1);
> +static_assert(std::is_same_v<decltype(e1), const std::dextents<size_t,
> 1>>);
> +static_assert(e1 == std::extents<size_t, 1>());
> +
> +constexpr auto e2 = std::extents(1.0, 2.0f);
> +static_assert(std::is_same_v<decltype(e2), const std::dextents<size_t,
> 2>>);
> +static_assert(e2 == std::extents<size_t, 1, 2>());
> +
> +constexpr auto e3 = std::extents(int(1), char(2), size_t(3));
> +static_assert(std::is_same_v<decltype(e3), const std::dextents<size_t,
> 3>>);
> +static_assert(e3 == std::extents<size_t, 1, 2, 3>());
> +
> +class A {};
> +
> +template<typename... Extents>
> +  concept deducible = requires
> +  {
> +    { std::extents(Extents{}...) }
> +      -> std::convertible_to<std::dextents<size_t, sizeof...(Extents)>>;
> +  };
> +
> +static_assert(deducible<int>);
> +static_assert(!deducible<A, A>);
> diff --git
> a/libstdc++-v3/testsuite/23_containers/mdspan/extents/dextents.cc
> b/libstdc++-v3/testsuite/23_containers/mdspan/extents/dextents.cc
> new file mode 100644
> index 00000000000..31544373c72
> --- /dev/null
> +++ b/libstdc++-v3/testsuite/23_containers/mdspan/extents/dextents.cc
> @@ -0,0 +1,11 @@
> +// { dg-do compile { target c++23 } }
> +#include <mdspan>
> +
> +#include <type_traits>
> +
> +constexpr auto dyn = std::dynamic_extent;
> +
> +static_assert(std::is_same_v<std::dextents<int, 0>, std::extents<int>>);
> +static_assert(std::is_same_v<std::dextents<int, 1>, std::extents<int,
> dyn>>);
> +static_assert(std::is_same_v<std::dextents<int, 5>,
> +             std::extents<int, dyn, dyn, dyn, dyn, dyn>>);
> diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/extents/extent.cc
> b/libstdc++-v3/testsuite/23_containers/mdspan/extents/extent.cc
> new file mode 100644
> index 00000000000..1993fa31fc6
> --- /dev/null
> +++ b/libstdc++-v3/testsuite/23_containers/mdspan/extents/extent.cc
> @@ -0,0 +1,24 @@
> +// { dg-do compile { target c++23 } }
> +#include <mdspan>
> +
> +#include <testsuite_hooks.h>
> +
> +constexpr auto dyn = std::dynamic_extent;
> +
> +static_assert(std::extents<int, 1, 2>::static_extent(0) == 1);
> +static_assert(std::extents<int, 1, 2>::static_extent(1) == 2);
> +
> +static_assert(std::extents<int, 1, dyn>::static_extent(0) == 1);
> +static_assert(std::extents<int, 1, dyn>::static_extent(1) == dyn);
> +
> +static_assert(std::extents<int, dyn, dyn>::static_extent(0) == dyn);
> +static_assert(std::extents<int, dyn, dyn>::static_extent(1) == dyn);
> +
> +constexpr std::extents<int, 1, 2> e0;
> +static_assert(e0.extent(0) == 1 && e0.extent(1) == 2);
> +
> +constexpr std::extents<int, 1, dyn> e1(2);
> +static_assert(e1.extent(0) == 1 && e1.extent(1) == 2);
> +
> +constexpr std::extents<int, 1, dyn> e2(2);
> +static_assert(e2.extent(0) == 1 && e2.extent(1) == 2);
> diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/extents/ops_eq.cc
> b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ops_eq.cc
> new file mode 100644
> index 00000000000..4a1b0641d9d
> --- /dev/null
> +++ b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ops_eq.cc
> @@ -0,0 +1,58 @@
> +// { dg-do run { target c++23 } }
> +#include <mdspan>
> +
> +#include <testsuite_hooks.h>
> +
> +template<class Lhs, class Rhs>
> +  void
> +  test_ops_eq(const Lhs& lhs, const Rhs& rhs, bool expected)
> +  {
> +    VERIFY((lhs == rhs) == expected);
> +    VERIFY((lhs != rhs) == !expected);
> +  }
> +
> +constexpr auto dyn = std::dynamic_extent;
> +
> +static_assert(std::extents<int, 1, 2, 3>() == std::extents<int, 1, 2,
> 3>());
> +static_assert(std::extents<int, 1, 2, 3>() != std::extents<int, 1, 2>());
> +static_assert(std::extents<int, 1, 2, 3>() == std::extents<int, 1, dyn,
> 3>(2));
> +static_assert(std::extents<int, 1, 2, 3>() != std::extents<int, 1, dyn,
> 3>(3));
>
This is interesting consequence of allowing references to unknown,

> +
> +void
> +test_rank_zero()
> +{
> +  auto e1 = std::extents<int>();
> +  auto e2 = std::extents<int>();
> +  auto e3 = std::extents<unsigned int>();
> +
> +  test_ops_eq(e1, e2, true);
> +  test_ops_eq(e1, e3, true);
> +}
> +
> +void
> +test_common()
> +{
> +  auto e1 = std::extents<int, 1, 2, 3>();
> +  auto e2 = std::extents<int, 1, 2, 3>();
> +  auto e3 = std::extents<int, 1, dyn, 3>(2);
> +  auto e4 = std::extents<int, 1, dyn, 3>(3);
> +
> +  auto e5 = std::extents<int, 1>();
> +  auto e6 = std::extents<int, 1, 3, 3>();
> +
> +  test_ops_eq(e1, e2, true);
> +  test_ops_eq(e1, e3, true);
> +  test_ops_eq(e1, e4, false);
> +
> +  test_ops_eq(e1, e5, false);
> +  test_ops_eq(e1, e6, false);
> +  test_ops_eq(e3, e6, false);
> +}
> +
> +int
> +main()
> +{
> +  test_rank_zero();
> +  test_common();
> +  return 0;
> +}
> --
> 2.48.1
>
>

Reply via email to