Skip to content

Commit

Permalink
Merge pull request #285 from crtrott/fix-standard-compliance
Browse files Browse the repository at this point in the history
Fix standard compliance
  • Loading branch information
crtrott authored Oct 26, 2023
2 parents e8e1a78 + 8328f29 commit b186529
Show file tree
Hide file tree
Showing 32 changed files with 217 additions and 97 deletions.
4 changes: 3 additions & 1 deletion compilation_tests/ctest_layout_convertible.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,12 @@ MDSPAN_STATIC_TEST(
!std::is_convertible<AStridedLayout<false>::mapping<E2>, LS1>::value
);

#if !MDSPAN_HAS_CXX_14 && !MDSPAN_HAS_CXX_20
MDSPAN_STATIC_TEST(
std::is_constructible<LS2, AStridedLayout<true>::mapping<E1>>::value &&
std::is_convertible<AStridedLayout<true>::mapping<E1>, LS2>::value
!std::is_convertible<AStridedLayout<true>::mapping<E1>, LS2>::value
);
#endif

MDSPAN_STATIC_TEST(
!std::is_constructible<LS1, NotARealLayout::mapping<E2>>::value
Expand Down
7 changes: 7 additions & 0 deletions include/experimental/__p0009_bits/config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,17 @@
#define MDSPAN_CXX_STD_14 201402L
#define MDSPAN_CXX_STD_17 201703L
#define MDSPAN_CXX_STD_20 202002L
// Note GCC has not updated this in version 13
#ifdef __clang__
#define MDSPAN_CXX_STD_23 202302L
#else
#define MDSPAN_CXX_STD_23 202100L
#endif

#define MDSPAN_HAS_CXX_14 (_MDSPAN_CPLUSPLUS >= MDSPAN_CXX_STD_14)
#define MDSPAN_HAS_CXX_17 (_MDSPAN_CPLUSPLUS >= MDSPAN_CXX_STD_17)
#define MDSPAN_HAS_CXX_20 (_MDSPAN_CPLUSPLUS >= MDSPAN_CXX_STD_20)
#define MDSPAN_HAS_CXX_23 (_MDSPAN_CPLUSPLUS >= MDSPAN_CXX_STD_23)

static_assert(_MDSPAN_CPLUSPLUS >= MDSPAN_CXX_STD_14, "mdspan requires C++14 or later.");

Expand Down
29 changes: 19 additions & 10 deletions include/experimental/__p0009_bits/extents.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -251,12 +251,17 @@ struct maybe_static_array {

#ifdef __cpp_lib_span
MDSPAN_TEMPLATE_REQUIRES(class T, size_t N,
/* requires */ (N == m_size_dynamic))
/* requires */ (N == m_size_dynamic && N > 0))
MDSPAN_INLINE_FUNCTION
constexpr maybe_static_array(const std::span<T, N> &vals) {
for (size_t r = 0; r < N; r++)
m_dyn_vals[r] = static_cast<TDynamic>(vals[r]);
}

MDSPAN_TEMPLATE_REQUIRES(class T, size_t N,
/* requires */ (N == m_size_dynamic && N == 0))
MDSPAN_INLINE_FUNCTION
constexpr maybe_static_array(const std::span<T, N> &) : m_dyn_vals{} {}
#endif

// constructors from all values
Expand Down Expand Up @@ -423,9 +428,9 @@ template <class IndexType, size_t... Extents> class extents {
class OtherIndexType, size_t N,
/* requires */
(
_MDSPAN_TRAIT(std::is_convertible, OtherIndexType, index_type) &&
_MDSPAN_TRAIT(std::is_convertible, const OtherIndexType&, index_type) &&
_MDSPAN_TRAIT(std::is_nothrow_constructible, index_type,
OtherIndexType) &&
const OtherIndexType&) &&
(N == m_rank || N == m_rank_dynamic)))
MDSPAN_INLINE_FUNCTION
MDSPAN_CONDITIONAL_EXPLICIT(N != m_rank_dynamic)
Expand All @@ -436,8 +441,8 @@ template <class IndexType, size_t... Extents> class extents {
MDSPAN_TEMPLATE_REQUIRES(
class OtherIndexType, size_t N,
/* requires */
(_MDSPAN_TRAIT(std::is_convertible, OtherIndexType, index_type) &&
_MDSPAN_TRAIT(std::is_nothrow_constructible, index_type, OtherIndexType) &&
(_MDSPAN_TRAIT(std::is_convertible, const OtherIndexType&, index_type) &&
_MDSPAN_TRAIT(std::is_nothrow_constructible, index_type, const OtherIndexType&) &&
(N == m_rank || N == m_rank_dynamic)))
MDSPAN_INLINE_FUNCTION
MDSPAN_CONDITIONAL_EXPLICIT(N != m_rank_dynamic)
Expand Down Expand Up @@ -521,10 +526,14 @@ template <class IndexType, size_t... Extents> class extents {
MDSPAN_INLINE_FUNCTION friend constexpr bool
operator==(const extents &lhs,
const extents<OtherIndexType, OtherExtents...> &rhs) noexcept {
bool value = true;
for (size_type r = 0; r < m_rank; r++)
value &= rhs.extent(r) == lhs.extent(r);
return value;
if constexpr (rank() != extents<OtherIndexType, OtherExtents...>::rank()) {
return false;
} else {
using common_t = std::common_type_t<index_type, OtherIndexType>;
for (size_type r = 0; r < m_rank; r++)
if(static_cast<common_t>(rhs.extent(r)) != static_cast<common_t>(lhs.extent(r))) return false;
}
return true;
}

#if !(MDSPAN_HAS_CXX_20)
Expand Down Expand Up @@ -573,7 +582,7 @@ using dextents = typename detail::__make_dextents<IndexType, Rank>::type;
template <class... IndexTypes>
extents(IndexTypes...)
-> extents<size_t,
size_t((IndexTypes(), ::MDSPAN_IMPL_STANDARD_NAMESPACE::dynamic_extent))...>;
((void) sizeof(IndexTypes), ::MDSPAN_IMPL_STANDARD_NAMESPACE::dynamic_extent)...>;
#endif

// Helper type traits for identifying a class as extents.
Expand Down
31 changes: 20 additions & 11 deletions include/experimental/__p0009_bits/layout_left.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
#include "trait_backports.hpp"
#include "extents.hpp"
#include "../__p2642_bits/layout_padded_fwd.hpp"
#include <cassert>
#include <type_traits>

namespace MDSPAN_IMPL_STANDARD_NAMESPACE {

Expand Down Expand Up @@ -155,13 +157,14 @@ class layout_left::mapping {
* other.required_span_size() is a representable value of type index_type
*/
#if !defined(_MDSPAN_HAS_CUDA) && !defined(_MDSPAN_HAS_HIP) && !defined(NDEBUG)
index_type stride = 1;
for(rank_type r=0; r<__extents.rank(); r++) {
if(stride != static_cast<index_type>(other.stride(r))) {
// Note this throw will lead to a terminate if triggered since this function is marked noexcept
throw std::runtime_error("Assigning layout_stride to layout_left with invalid strides.");
if constexpr (extents_type::rank() > 0) {
index_type stride = 1;
using common_t = std::common_type_t<index_type, typename OtherExtents::index_type>;
for(rank_type r=0; r<__extents.rank(); r++) {
if(static_cast<common_t>(stride) != static_cast<common_t>(other.stride(r)))
std::abort(); // ("Assigning layout_stride to layout_left with invalid strides.");
stride *= __extents.extent(r);
}
stride *= __extents.extent(r);
}
#endif
}
Expand Down Expand Up @@ -203,9 +206,9 @@ class layout_left::mapping {
MDSPAN_INLINE_FUNCTION static constexpr bool is_always_exhaustive() noexcept { return true; }
MDSPAN_INLINE_FUNCTION static constexpr bool is_always_strided() noexcept { return true; }

MDSPAN_INLINE_FUNCTION constexpr bool is_unique() const noexcept { return true; }
MDSPAN_INLINE_FUNCTION constexpr bool is_exhaustive() const noexcept { return true; }
MDSPAN_INLINE_FUNCTION constexpr bool is_strided() const noexcept { return true; }
MDSPAN_INLINE_FUNCTION static constexpr bool is_unique() noexcept { return true; }
MDSPAN_INLINE_FUNCTION static constexpr bool is_exhaustive() noexcept { return true; }
MDSPAN_INLINE_FUNCTION static constexpr bool is_strided() noexcept { return true; }

MDSPAN_INLINE_FUNCTION
constexpr index_type stride(rank_type i) const noexcept
Expand All @@ -218,15 +221,21 @@ class layout_left::mapping {
return value;
}

template<class OtherExtents>
MDSPAN_TEMPLATE_REQUIRES(
class OtherExtents,
/* requires */ ( Extents::rank() == OtherExtents::rank())
)
MDSPAN_INLINE_FUNCTION
friend constexpr bool operator==(mapping const& lhs, mapping<OtherExtents> const& rhs) noexcept {
return lhs.extents() == rhs.extents();
}

// In C++ 20 the not equal exists if equal is found
#if !(MDSPAN_HAS_CXX_20)
template<class OtherExtents>
MDSPAN_TEMPLATE_REQUIRES(
class OtherExtents,
/* requires */ ( Extents::rank() == OtherExtents::rank())
)
MDSPAN_INLINE_FUNCTION
friend constexpr bool operator!=(mapping const& lhs, mapping<OtherExtents> const& rhs) noexcept {
return lhs.extents() != rhs.extents();
Expand Down
30 changes: 19 additions & 11 deletions include/experimental/__p0009_bits/layout_right.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -158,13 +158,15 @@ class layout_right::mapping {
* other.required_span_size() is a representable value of type index_type
*/
#if !defined(_MDSPAN_HAS_CUDA) && !defined(_MDSPAN_HAS_HIP) && !defined(NDEBUG)
index_type stride = 1;
for(rank_type r=__extents.rank(); r>0; r--) {
if(stride != static_cast<index_type>(other.stride(r-1))) {
// Note this throw will lead to a terminate if triggered since this function is marked noexcept
throw std::runtime_error("Assigning layout_stride to layout_right with invalid strides.");
if constexpr (extents_type::rank() > 0) {
index_type stride = 1;
for(rank_type r=__extents.rank(); r>0; r--) {
if(stride != static_cast<index_type>(other.stride(r-1))) {
// Note this throw will lead to a terminate if triggered since this function is marked noexcept
throw std::runtime_error("Assigning layout_stride to layout_right with invalid strides.");
}
stride *= __extents.extent(r-1);
}
stride *= __extents.extent(r-1);
}
#endif
}
Expand Down Expand Up @@ -203,9 +205,9 @@ class layout_right::mapping {
MDSPAN_INLINE_FUNCTION static constexpr bool is_always_unique() noexcept { return true; }
MDSPAN_INLINE_FUNCTION static constexpr bool is_always_exhaustive() noexcept { return true; }
MDSPAN_INLINE_FUNCTION static constexpr bool is_always_strided() noexcept { return true; }
MDSPAN_INLINE_FUNCTION constexpr bool is_unique() const noexcept { return true; }
MDSPAN_INLINE_FUNCTION constexpr bool is_exhaustive() const noexcept { return true; }
MDSPAN_INLINE_FUNCTION constexpr bool is_strided() const noexcept { return true; }
MDSPAN_INLINE_FUNCTION static constexpr bool is_unique() noexcept { return true; }
MDSPAN_INLINE_FUNCTION static constexpr bool is_exhaustive() noexcept { return true; }
MDSPAN_INLINE_FUNCTION static constexpr bool is_strided() noexcept { return true; }

MDSPAN_INLINE_FUNCTION
constexpr index_type stride(rank_type i) const noexcept
Expand All @@ -218,15 +220,21 @@ class layout_right::mapping {
return value;
}

template<class OtherExtents>
MDSPAN_TEMPLATE_REQUIRES(
class OtherExtents,
/* requires */ ( Extents::rank() == OtherExtents::rank())
)
MDSPAN_INLINE_FUNCTION
friend constexpr bool operator==(mapping const& lhs, mapping<OtherExtents> const& rhs) noexcept {
return lhs.extents() == rhs.extents();
}

// In C++ 20 the not equal exists if equal is found
#if !(MDSPAN_HAS_CXX_20)
template<class OtherExtents>
MDSPAN_TEMPLATE_REQUIRES(
class OtherExtents,
/* requires */ (Extents::rank() == OtherExtents::rank())
)
MDSPAN_INLINE_FUNCTION
friend constexpr bool operator!=(mapping const& lhs, mapping<OtherExtents> const& rhs) noexcept {
return lhs.extents() != rhs.extents();
Expand Down
94 changes: 74 additions & 20 deletions include/experimental/__p0009_bits/layout_stride.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ struct layout_stride {

//----------------------------------------------------------------------------

using __strides_storage_t = std::array<index_type, extents_type::rank()>;
using __strides_storage_t = detail::possibly_empty_array<index_type, extents_type::rank()>;
using __member_pair_t = detail::__compressed_pair<extents_type, __strides_storage_t>;

#if defined(_MDSPAN_USE_ATTRIBUTE_NO_UNIQUE_ADDRESS)
Expand Down Expand Up @@ -158,14 +158,16 @@ struct layout_stride {
template <class OtherExtents>
MDSPAN_INLINE_FUNCTION
static constexpr bool _eq_impl(mapping const& self, mapping<OtherExtents> const& other) noexcept {
return _MDSPAN_FOLD_AND((self.stride(Idxs) == other.stride(Idxs)) /* && ... */)
&& _MDSPAN_FOLD_AND((self.extents().extent(Idxs) == other.extents().extent(Idxs)) /* || ... */);
using common_t = std::common_type_t<index_type, typename OtherExtents::index_type>;
return _MDSPAN_FOLD_AND((static_cast<common_t>(self.stride(Idxs)) == static_cast<common_t>(other.stride(Idxs))) /* && ... */)
&& _MDSPAN_FOLD_AND((static_cast<common_t>(self.extents().extent(Idxs)) == static_cast<common_t>(other.extents().extent(Idxs))) /* || ... */);
}
template <class OtherExtents>
MDSPAN_INLINE_FUNCTION
static constexpr bool _not_eq_impl(mapping const& self, mapping<OtherExtents> const& other) noexcept {
return _MDSPAN_FOLD_OR((self.stride(Idxs) != other.stride(Idxs)) /* || ... */)
|| _MDSPAN_FOLD_OR((self.extents().extent(Idxs) != other.extents().extent(Idxs)) /* || ... */);
using common_t = std::common_type_t<index_type, typename OtherExtents::index_type>;
return _MDSPAN_FOLD_OR((static_cast<common_t>(self.stride(Idxs)) != static_cast<common_t>(other.stride(Idxs))) /* || ... */)
|| _MDSPAN_FOLD_OR((static_cast<common_t>(self.extents().extent(Idxs)) != static_cast<common_t>(other.extents().extent(Idxs))) /* || ... */);
}

template <class... Integral>
Expand Down Expand Up @@ -205,6 +207,11 @@ struct layout_stride {
}
#endif

MDSPAN_INLINE_FUNCTION
static constexpr std::array<index_type, extents_type::rank()> return_strides(const __strides_storage_t& s) {
return std::array<index_type, extents_type::rank()>{s[Idxs]...};
}

template<size_t K>
MDSPAN_INLINE_FUNCTION
static constexpr size_t __return_zero() { return 0; }
Expand Down Expand Up @@ -233,7 +240,31 @@ struct layout_stride {

//--------------------------------------------------------------------------------

MDSPAN_INLINE_FUNCTION_DEFAULTED constexpr mapping() noexcept = default;
MDSPAN_INLINE_FUNCTION_DEFAULTED constexpr mapping() noexcept
#if defined(_MDSPAN_USE_ATTRIBUTE_NO_UNIQUE_ADDRESS)
: __members{
#else
: __base_t(__base_t{__member_pair_t(
#endif
extents_type(), __strides_storage_t([]() {
__strides_storage_t s{};
if constexpr (extents_type::rank() > 0) {
extents_type e;
index_type stride = 1;
for(int r = static_cast<int>(extents_type::rank() - 1); r >= 0; r--) {
s[r] = stride;
stride *= e.extent(r);
}
}
return s;
}())
#if defined(_MDSPAN_USE_ATTRIBUTE_NO_UNIQUE_ADDRESS)
}
#else
)})
#endif
{}

MDSPAN_INLINE_FUNCTION_DEFAULTED constexpr mapping(mapping const&) noexcept = default;

MDSPAN_TEMPLATE_REQUIRES(
Expand Down Expand Up @@ -332,10 +363,10 @@ struct layout_stride {
)
#endif
MDSPAN_CONDITIONAL_EXPLICIT(
(!std::is_convertible<typename StridedLayoutMapping::extents_type, extents_type>::value) &&
(detail::__is_mapping_of<layout_left, StridedLayoutMapping> ||
detail::__is_mapping_of<layout_right, StridedLayoutMapping> ||
detail::__is_mapping_of<layout_stride, StridedLayoutMapping>)
!(std::is_convertible<typename StridedLayoutMapping::extents_type, extents_type>::value &&
(detail::__is_mapping_of<layout_left, StridedLayoutMapping> ||
detail::__is_mapping_of<layout_right, StridedLayoutMapping> ||
detail::__is_mapping_of<layout_stride, StridedLayoutMapping>))
) // needs two () due to comma
MDSPAN_INLINE_FUNCTION _MDSPAN_CONSTEXPR_14
mapping(StridedLayoutMapping const& other) noexcept // NOLINT(google-explicit-constructor)
Expand Down Expand Up @@ -374,7 +405,7 @@ struct layout_stride {

MDSPAN_INLINE_FUNCTION
constexpr std::array< index_type, extents_type::rank() > strides() const noexcept {
return __strides_storage();
return __impl::return_strides(__strides_storage());
}

MDSPAN_INLINE_FUNCTION
Expand Down Expand Up @@ -410,17 +441,37 @@ struct layout_stride {

MDSPAN_INLINE_FUNCTION static constexpr bool is_unique() noexcept { return true; }
MDSPAN_INLINE_FUNCTION _MDSPAN_CONSTEXPR_14 bool is_exhaustive() const noexcept {
return required_span_size() == __get_size(extents(), std::make_index_sequence<extents_type::rank()>());
if constexpr (extents_type::rank() == 0)
return true;
else {
index_type span_size = required_span_size();
if (span_size == static_cast<index_type>(0)) {
if constexpr (extents_type::rank() == 1) {
return stride(0) == 1;
} else {
rank_type r_largest = 0;
for (rank_type r = 1; r < extents_type::rank(); r++) {
if (stride(r) > stride(r_largest)) {
r_largest = r;
}
}
for (rank_type r = 0; r < extents_type::rank(); r++) {
if (extents().extent(r) == 0 && r != r_largest) {
return false;
}
}
return true;
}
} else {
return required_span_size() == __get_size(extents(), std::make_index_sequence<extents_type::rank()>());
}
}
}
MDSPAN_INLINE_FUNCTION static constexpr bool is_strided() noexcept { return true; }


MDSPAN_INLINE_FUNCTION
constexpr index_type stride(rank_type r) const noexcept
#if MDSPAN_HAS_CXX_20
requires ( Extents::rank() > 0 )
#endif
{
constexpr index_type stride(rank_type r) const noexcept {
return __strides_storage()[r];
}

Expand All @@ -444,10 +495,13 @@ struct layout_stride {
MDSPAN_INLINE_FUNCTION
friend constexpr bool operator==(const mapping& x, const StridedLayoutMapping& y) noexcept {
bool strides_match = true;
for(rank_type r = 0; r < extents_type::rank(); r++)
strides_match = strides_match && (x.stride(r) == y.stride(r));
if constexpr (extents_type::rank() > 0) {
using common_t = std::common_type_t<index_type, typename StridedLayoutMapping::index_type>;
for(rank_type r = 0; r < extents_type::rank(); r++)
strides_match = strides_match && (static_cast<common_t>(x.stride(r)) == static_cast<common_t>(y.stride(r)));
}
return (x.extents() == y.extents()) &&
(__impl::__OFFSET(y)== static_cast<typename StridedLayoutMapping::index_type>(0)) &&
(__impl::__OFFSET(y) == static_cast<typename StridedLayoutMapping::index_type>(0)) &&
strides_match;
}

Expand Down
Loading

0 comments on commit b186529

Please sign in to comment.