#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.
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);
-}
+template<typename Extents, bool Valid>
+ void
+ test_shape(const auto& shape)
+ {
+ static_assert(std::is_constructible_v<Extents, decltype(shape)> == Valid);
+
+ if constexpr (Valid)
+ {
+ std::extents<int, 2, 3> expected;
+ Extents actual(shape);
+ VERIFY(actual == 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);
+
+ auto a23 = std::array<Int, 2>{Int(2), Int(3)};
+ auto s23 = std::span<Int, 2>(a23);
+
+ 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);
+ };
+
+ check(a2, a23);
+ check(s2, s23);
+ }
+
+// 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>;
+ };
+
+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);
+
+ 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;
}
+++ /dev/null
-#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
--- /dev/null
+#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
// { dg-do run { target c++23 } }
#include <mdspan>
+#include "../int_like.h"
#include <cstdint>
#include <testsuite_hooks.h>
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>
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>
}
};
-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>
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>
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>();
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>();
// { dg-do run { target c++23 } }
#include <mdspan>
+#include "../int_like.h"
#include <testsuite_hooks.h>
constexpr size_t dyn = std::dynamic_extent;
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()
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>();
#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;
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);
-
- 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);
- };
+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{};
- 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));
-}
+ 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);
+ };
+
+ 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>
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)>);
-
- 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 mapping = std::layout_left::mapping(exts);
+ constexpr size_t n = mapping.required_span_size();
+ std::array<double, n> storage{};
+
+ 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()
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());