We've built up quite a few links directly to github within the code base. We should instead use `llvm.org/PR<issue-number>` to link to bugs, since that is resilient to the bug tracker changing in the future. This is especially relevant for tests linking to bugs, since they will probably be there for decades to come. A nice side effect is that these links are significantly shorter than the GH links, making them much less of an eyesore. This patch also replaces a few links that linked to the old bugzilla instance on llvm.org.
285 lines
17 KiB
C++
285 lines
17 KiB
C++
//===----------------------------------------------------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
|
|
|
|
// MSVC warning C4244: 'initializing': conversion from '_Ty' to '_Ty', possible loss of data
|
|
// ADDITIONAL_COMPILE_FLAGS(cl-style-warnings): /wd4244
|
|
|
|
// <mdspan>
|
|
|
|
// template<class OtherElementType, class OtherExtents,
|
|
// class OtherLayoutPolicy, class OtherAccessor>
|
|
// constexpr explicit(see below)
|
|
// mdspan(const mdspan<OtherElementType, OtherExtents,
|
|
// OtherLayoutPolicy, OtherAccessor>& other);
|
|
//
|
|
// Constraints:
|
|
// - is_constructible_v<mapping_type, const OtherLayoutPolicy::template mapping<OtherExtents>&> is true, and
|
|
// - is_constructible_v<accessor_type, const OtherAccessor&> is true.
|
|
// Mandates:
|
|
// - is_constructible_v<data_handle_type, const OtherAccessor::data_handle_type&> is
|
|
// - is_constructible_v<extents_type, OtherExtents> is true.
|
|
//
|
|
// Preconditions:
|
|
// - For each rank index r of extents_type, static_extent(r) == dynamic_extent || static_extent(r) == other.extent(r) is true.
|
|
// - [0, map_.required_span_size()) is an accessible range of ptr_ and acc_ for values of ptr_, map_, and acc_ after the invocation of this constructor.
|
|
//
|
|
// Effects:
|
|
// - Direct-non-list-initializes ptr_ with other.ptr_,
|
|
// - direct-non-list-initializes map_ with other.map_, and
|
|
// - direct-non-list-initializes acc_ with other.acc_.
|
|
//
|
|
// Remarks: The expression inside explicit is equivalent to:
|
|
// !is_convertible_v<const OtherLayoutPolicy::template mapping<OtherExtents>&, mapping_type>
|
|
// || !is_convertible_v<const OtherAccessor&, accessor_type>
|
|
|
|
#include <mdspan>
|
|
#include <cassert>
|
|
#include <concepts>
|
|
#include <type_traits>
|
|
|
|
#include "test_macros.h"
|
|
|
|
#include "../MinimalElementType.h"
|
|
#include "../CustomTestLayouts.h"
|
|
#include "CustomTestAccessors.h"
|
|
|
|
template <class ToMDS, class FromMDS>
|
|
constexpr void test_implicit_conversion(ToMDS to_mds, FromMDS from_mds) {
|
|
assert(to_mds.extents() == from_mds.extents());
|
|
if constexpr (std::equality_comparable_with<typename ToMDS::data_handle_type, typename FromMDS::data_handle_type>)
|
|
assert(to_mds.data_handle() == from_mds.data_handle());
|
|
if constexpr (std::equality_comparable_with<typename ToMDS::mapping_type, typename FromMDS::mapping_type>)
|
|
assert(to_mds.mapping() == from_mds.mapping());
|
|
if constexpr (std::equality_comparable_with<typename ToMDS::accessor_type, typename FromMDS::accessor_type>)
|
|
assert(to_mds.accessor() == from_mds.accessor());
|
|
}
|
|
|
|
template <class M>
|
|
concept mapping_requirements = requires() {
|
|
requires(std::copyable<M> && std::equality_comparable<M>) && std::is_nothrow_move_constructible_v<M> &&
|
|
std::is_nothrow_move_assignable_v<M> && std::is_nothrow_swappable_v<M>;
|
|
};
|
|
|
|
template <class ToMDS, class FromMDS>
|
|
constexpr void test_conversion(FromMDS from_mds) {
|
|
// check some requirements, to see we didn't screw up our test layouts/accessors
|
|
static_assert(mapping_requirements<typename ToMDS::mapping_type>);
|
|
static_assert(mapping_requirements<typename FromMDS::mapping_type>);
|
|
|
|
constexpr bool constructible =
|
|
std::is_constructible_v<typename ToMDS::mapping_type, const typename FromMDS::mapping_type&> &&
|
|
std::is_constructible_v<typename ToMDS::accessor_type, const typename FromMDS::accessor_type&>;
|
|
constexpr bool convertible =
|
|
std::is_convertible_v<const typename FromMDS::mapping_type&, typename ToMDS::mapping_type> &&
|
|
std::is_convertible_v<const typename FromMDS::accessor_type&, typename ToMDS::accessor_type>;
|
|
constexpr bool passes_mandates =
|
|
std::is_constructible_v<typename ToMDS::data_handle_type, const typename FromMDS::data_handle_type&> &&
|
|
std::is_constructible_v<typename ToMDS::extents_type, typename FromMDS::extents_type>;
|
|
|
|
if constexpr (constructible) {
|
|
if constexpr (passes_mandates) {
|
|
ToMDS to_mds(from_mds);
|
|
assert(to_mds.extents() == from_mds.extents());
|
|
if constexpr (std::equality_comparable_with<typename ToMDS::data_handle_type, typename FromMDS::data_handle_type>)
|
|
assert(to_mds.data_handle() == from_mds.data_handle());
|
|
if constexpr (std::equality_comparable_with<typename ToMDS::mapping_type, typename FromMDS::mapping_type>)
|
|
assert(to_mds.mapping() == from_mds.mapping());
|
|
if constexpr (std::equality_comparable_with<typename ToMDS::accessor_type, typename FromMDS::accessor_type>)
|
|
assert(to_mds.accessor() == from_mds.accessor());
|
|
if constexpr (convertible) {
|
|
test_implicit_conversion(from_mds, from_mds);
|
|
} else {
|
|
static_assert(!std::is_convertible_v<FromMDS, ToMDS>);
|
|
}
|
|
}
|
|
} else {
|
|
static_assert(!std::is_constructible_v<ToMDS, FromMDS>);
|
|
}
|
|
}
|
|
|
|
template <class ToL, class ToE, class ToA, class FromH, class FromL, class FromE, class FromA>
|
|
constexpr void construct_from_mds(const FromH& handle, const FromL& layout, const FromE& exts, const FromA& acc) {
|
|
using ToMDS = std::mdspan<typename ToA::element_type, ToE, ToL, ToA>;
|
|
using FromMDS = std::mdspan<typename FromA::element_type, FromE, FromL, FromA>;
|
|
test_conversion<ToMDS>(FromMDS(handle, construct_mapping(layout, exts), acc));
|
|
}
|
|
|
|
template <class ToL, class ToA, class FromH, class FromL, class FromA>
|
|
constexpr void mixin_extents(const FromH& handle, const FromL& layout, const FromA& acc) {
|
|
constexpr size_t D = std::dynamic_extent;
|
|
// constructible and convertible
|
|
construct_from_mds<ToL, std::dextents<int, 0>, ToA>(handle, layout, std::dextents<int, 0>(), acc);
|
|
construct_from_mds<ToL, std::dextents<int, 1>, ToA>(handle, layout, std::dextents<int, 1>(4), acc);
|
|
construct_from_mds<ToL, std::dextents<int, 1>, ToA>(handle, layout, std::extents<int, 4>(), acc);
|
|
construct_from_mds<ToL, std::dextents<int, 2>, ToA>(handle, layout, std::dextents<int, 2>(4, 5), acc);
|
|
construct_from_mds<ToL, std::dextents<unsigned, 2>, ToA>(handle, layout, std::dextents<int, 2>(4, 5), acc);
|
|
construct_from_mds<ToL, std::dextents<unsigned, 2>, ToA>(handle, layout, std::extents<int, D, 5>(4), acc);
|
|
construct_from_mds<ToL, std::extents<int, D, 5>, ToA>(handle, layout, std::extents<int, D, 5>(4), acc);
|
|
construct_from_mds<ToL, std::extents<int, D, 5>, ToA>(handle, layout, std::extents<int, D, 5>(4), acc);
|
|
construct_from_mds<ToL, std::extents<int, D, 5, D, 7>, ToA>(handle, layout, std::extents<int, D, 5, D, 7>(4, 6), acc);
|
|
|
|
// not convertible
|
|
construct_from_mds<ToL, std::dextents<int, 1>, ToA>(handle, layout, std::dextents<unsigned, 1>(4), acc);
|
|
construct_from_mds<ToL, std::extents<int, D, 5, D, 7>, ToA>(
|
|
handle, layout, std::extents<int, D, 5, D, D>(4, 6, 7), acc);
|
|
|
|
// not constructible
|
|
construct_from_mds<ToL, std::dextents<int, 1>, ToA>(handle, layout, std::dextents<int, 2>(4, 5), acc);
|
|
construct_from_mds<ToL, std::extents<int, D, 5, D, 8>, ToA>(handle, layout, std::extents<int, D, 5, D, 7>(4, 6), acc);
|
|
}
|
|
|
|
template <class ToA, class FromH, class FromA>
|
|
constexpr void mixin_layout(const FromH& handle, const FromA& acc) {
|
|
mixin_extents<std::layout_left, ToA>(handle, std::layout_left(), acc);
|
|
mixin_extents<std::layout_right, ToA>(handle, std::layout_right(), acc);
|
|
// Check layout policy conversion
|
|
// different layout policies, but constructible and convertible
|
|
static_assert(std::is_constructible_v<std::layout_left::mapping<std::dextents<int, 1>>,
|
|
const std::layout_right::mapping<std::dextents<int, 1>>&>);
|
|
static_assert(std::is_convertible_v<const std::layout_right::mapping<std::dextents<int, 1>>&,
|
|
std::layout_left::mapping<std::dextents<int, 1>>>);
|
|
// different layout policies, not constructible
|
|
static_assert(!std::is_constructible_v<std::layout_left::mapping<std::dextents<int, 2>>,
|
|
const std::layout_right::mapping<std::dextents<int, 2>>&>);
|
|
// different layout policies, constructible and not convertible
|
|
static_assert(std::is_constructible_v<std::layout_left::mapping<std::dextents<int, 1>>,
|
|
const std::layout_right::mapping<std::dextents<size_t, 1>>&>);
|
|
static_assert(!std::is_convertible_v<const std::layout_right::mapping<std::dextents<size_t, 1>>&,
|
|
std::layout_left::mapping<std::dextents<int, 1>>>);
|
|
|
|
mixin_extents<std::layout_left, ToA>(handle, std::layout_right(), acc);
|
|
mixin_extents<layout_wrapping_integral<4>, ToA>(handle, layout_wrapping_integral<4>(), acc);
|
|
// different layout policies, constructible and not convertible
|
|
static_assert(!std::is_constructible_v<layout_wrapping_integral<8>::mapping<std::dextents<unsigned, 2>>,
|
|
const layout_wrapping_integral<8>::mapping<std::dextents<int, 2>>&>);
|
|
static_assert(std::is_constructible_v<layout_wrapping_integral<8>::mapping<std::dextents<unsigned, 2>>,
|
|
layout_wrapping_integral<8>::mapping<std::dextents<int, 2>>>);
|
|
mixin_extents<layout_wrapping_integral<8>, ToA>(handle, layout_wrapping_integral<8>(), acc);
|
|
}
|
|
|
|
// check that we cover all corners with respect to constructibility and convertibility
|
|
template <bool constructible_constref_acc,
|
|
bool convertible_constref_acc,
|
|
bool constructible_nonconst_acc,
|
|
bool convertible_nonconst_acc,
|
|
bool constructible_constref_handle,
|
|
bool convertible_constref_handle,
|
|
bool constructible_nonconst_handle,
|
|
bool convertible_nonconst_handle,
|
|
class ToA,
|
|
class FromA>
|
|
constexpr bool test(FromA from_acc) {
|
|
static_assert(std::copyable<ToA>);
|
|
static_assert(std::copyable<FromA>);
|
|
static_assert(std::is_constructible_v<ToA, const FromA&> == constructible_constref_acc);
|
|
static_assert(std::is_constructible_v<ToA, FromA> == constructible_nonconst_acc);
|
|
static_assert(std::is_constructible_v<typename ToA::data_handle_type, const typename FromA::data_handle_type&> ==
|
|
constructible_constref_handle);
|
|
static_assert(std::is_constructible_v<typename ToA::data_handle_type, typename FromA::data_handle_type> ==
|
|
constructible_nonconst_handle);
|
|
static_assert(std::is_convertible_v<const FromA&, ToA> == convertible_constref_acc);
|
|
static_assert(std::is_convertible_v<FromA, ToA> == convertible_nonconst_acc);
|
|
static_assert(std::is_convertible_v<const typename FromA::data_handle_type&, typename ToA::data_handle_type> ==
|
|
convertible_constref_handle);
|
|
static_assert(std::is_convertible_v<typename FromA::data_handle_type, typename ToA::data_handle_type> ==
|
|
convertible_nonconst_handle);
|
|
|
|
ElementPool<typename FromA::element_type, 1024> elements;
|
|
mixin_layout<ToA>(typename FromA::data_handle_type(elements.get_ptr()), from_acc);
|
|
return true;
|
|
}
|
|
|
|
int main(int, char**) {
|
|
// using shorthands here: t and o for better visual distinguishability
|
|
constexpr bool t = true;
|
|
constexpr bool o = false;
|
|
|
|
// possibility matrix for constructibility and convertibility https://godbolt.org/z/98KGo8Wbc
|
|
// you can't have convertibility without constructibility
|
|
// and if you take const T& then you also can take T
|
|
// this leaves 7 combinations
|
|
// const_ref_ctor, const_ref_conv, nonconst_ctor, nonconst_conv, tested
|
|
// o o o o X
|
|
// o o t o X
|
|
// o o t t X
|
|
// t o t o X
|
|
// t o t t X
|
|
// t t t o X
|
|
// t t t t X
|
|
|
|
// checked_accessor has various weird data handles and some weird conversion properties
|
|
// conv_test_accessor_c/nc is an accessor pair which has configurable conversion properties, but plain ptr as data handle
|
|
// accessor constructible
|
|
test<t, t, t, t, t, t, t, t, std::default_accessor<float>>(std::default_accessor<float>());
|
|
test<t, t, t, t, t, t, t, t, std::default_accessor<const float>>(std::default_accessor<float>());
|
|
test<t, t, t, t, t, t, t, t, std::default_accessor<MinimalElementType>>(std::default_accessor<MinimalElementType>());
|
|
test<t, t, t, t, t, t, t, t, std::default_accessor<const MinimalElementType>>(
|
|
std::default_accessor<MinimalElementType>());
|
|
test<t, t, t, t, t, t, t, t, checked_accessor<int>>(checked_accessor<int>(1024));
|
|
test<t, o, t, o, t, t, t, t, checked_accessor<const int>>(checked_accessor<int>(1024));
|
|
test<t, t, t, t, o, o, o, o, checked_accessor<const unsigned>>(checked_accessor<unsigned>(1024));
|
|
test<t, t, t, t, t, t, t, t, checked_accessor<float>>(checked_accessor<float>(1024));
|
|
test<t, t, t, t, t, t, t, t, checked_accessor<double>>(checked_accessor<double>(1024));
|
|
test<t, t, t, t, t, t, t, t, checked_accessor<MinimalElementType>>(checked_accessor<MinimalElementType>(1024));
|
|
test<t, o, t, o, t, t, t, t, checked_accessor<const MinimalElementType>>(checked_accessor<MinimalElementType>(1024));
|
|
test<t, o, t, o, t, t, t, t, conv_test_accessor_c<int, t, t, t, t>>(conv_test_accessor_nc<int, t, t>());
|
|
test<t, o, t, t, t, t, t, t, conv_test_accessor_c<int, t, t, o, o>>(conv_test_accessor_nc<int, t, o>());
|
|
// FIXME: these tests trigger what appears to be a compiler bug on MINGW32 with --target=x86_64-w64-windows-gnu
|
|
// https://godbolt.org/z/KK8aj5bs7
|
|
// Bug report: https://llvm.org/PR64077
|
|
#ifndef __MINGW32__
|
|
test<t, t, t, o, t, t, t, t, conv_test_accessor_c<int, o, t, t, t>>(conv_test_accessor_nc<int, t, t>());
|
|
test<t, t, t, t, t, t, t, t, conv_test_accessor_c<int, o, o, o, o>>(conv_test_accessor_nc<int, t, o>());
|
|
#endif
|
|
|
|
// ElementType convertible, but accessor not constructible
|
|
test<o, o, o, o, o, o, o, o, std::default_accessor<float>>(std::default_accessor<int>());
|
|
test<o, o, o, o, o, o, o, o, checked_accessor<const double>>(checked_accessor<double>(1024));
|
|
test<o, o, t, t, t, t, t, t, checked_accessor<const float>>(checked_accessor<float>(1024));
|
|
test<o, o, o, o, t, t, t, t, conv_test_accessor_c<int, o, o, t, t>>(conv_test_accessor_nc<int, o, o>());
|
|
test<o, o, t, o, t, t, t, t, conv_test_accessor_c<int, o, t, o, o>>(conv_test_accessor_nc<int, o, t>());
|
|
test<o, o, t, t, t, t, t, t, conv_test_accessor_c<int, o, o, t, t>>(conv_test_accessor_nc<int, o, t>());
|
|
|
|
// Ran into trouble with doing it all in one static_assert: exceeding step limit for consteval
|
|
static_assert(test<t, t, t, t, t, t, t, t, std::default_accessor<float>>(std::default_accessor<float>()));
|
|
static_assert(test<t, t, t, t, t, t, t, t, std::default_accessor<const float>>(std::default_accessor<float>()));
|
|
static_assert(test<t, t, t, t, t, t, t, t, std::default_accessor<MinimalElementType>>(
|
|
std::default_accessor<MinimalElementType>()));
|
|
static_assert(test<t, t, t, t, t, t, t, t, std::default_accessor<const MinimalElementType>>(
|
|
std::default_accessor<MinimalElementType>()));
|
|
static_assert(test<t, t, t, t, t, t, t, t, checked_accessor<int>>(checked_accessor<int>(1024)));
|
|
static_assert(test<t, o, t, o, t, t, t, t, checked_accessor<const int>>(checked_accessor<int>(1024)));
|
|
static_assert(test<t, t, t, t, o, o, o, o, checked_accessor<const unsigned>>(checked_accessor<unsigned>(1024)));
|
|
static_assert(test<t, t, t, t, t, t, t, t, checked_accessor<float>>(checked_accessor<float>(1024)));
|
|
static_assert(test<t, t, t, t, t, t, t, t, checked_accessor<double>>(checked_accessor<double>(1024)));
|
|
static_assert(
|
|
test<t, t, t, t, t, t, t, t, checked_accessor<MinimalElementType>>(checked_accessor<MinimalElementType>(1024)));
|
|
static_assert(test<t, o, t, o, t, t, t, t, checked_accessor<const MinimalElementType>>(
|
|
checked_accessor<MinimalElementType>(1024)));
|
|
static_assert(
|
|
test<t, o, t, o, t, t, t, t, conv_test_accessor_c<int, t, t, t, t>>(conv_test_accessor_nc<int, t, t>()));
|
|
static_assert(
|
|
test<t, o, t, t, t, t, t, t, conv_test_accessor_c<int, t, t, o, o>>(conv_test_accessor_nc<int, t, o>()));
|
|
static_assert(
|
|
test<t, t, t, o, t, t, t, t, conv_test_accessor_c<int, o, t, t, t>>(conv_test_accessor_nc<int, t, t>()));
|
|
static_assert(
|
|
test<t, t, t, t, t, t, t, t, conv_test_accessor_c<int, o, o, o, o>>(conv_test_accessor_nc<int, t, o>()));
|
|
static_assert(test<o, o, o, o, o, o, o, o, std::default_accessor<float>>(std::default_accessor<int>()));
|
|
static_assert(test<o, o, o, o, o, o, o, o, checked_accessor<const double>>(checked_accessor<double>(1024)));
|
|
static_assert(test<o, o, t, t, t, t, t, t, checked_accessor<const float>>(checked_accessor<float>(1024)));
|
|
static_assert(
|
|
test<o, o, o, o, t, t, t, t, conv_test_accessor_c<int, o, o, t, t>>(conv_test_accessor_nc<int, o, o>()));
|
|
static_assert(
|
|
test<o, o, t, o, t, t, t, t, conv_test_accessor_c<int, o, t, o, o>>(conv_test_accessor_nc<int, o, t>()));
|
|
static_assert(
|
|
test<o, o, t, t, t, t, t, t, conv_test_accessor_c<int, o, o, t, t>>(conv_test_accessor_nc<int, o, t>()));
|
|
|
|
return 0;
|
|
}
|