diff --git a/include/experimental/__p0009_bits/utility.hpp b/include/experimental/__p0009_bits/utility.hpp index 33e5d0f1..acadd6f7 100644 --- a/include/experimental/__p0009_bits/utility.hpp +++ b/include/experimental/__p0009_bits/utility.hpp @@ -14,6 +14,14 @@ namespace MDSPAN_IMPL_STANDARD_NAMESPACE { namespace detail { +// Backport of std::remove_cvref / std::remove_cvref_t (C++20) +#if (__cplusplus >= 202002L) + using std::remove_cvref_t; +#else + template + using remove_cvref_t = std::remove_cv_t>; +#endif // __cplusplus >= 202002L + // type alias used for rank-based tag dispatch // // this is used to enable alternatives to constexpr if when building for C++14 diff --git a/include/experimental/__p2630_bits/integral_constant_like.hpp b/include/experimental/__p2630_bits/integral_constant_like.hpp new file mode 100644 index 00000000..ab69f66a --- /dev/null +++ b/include/experimental/__p2630_bits/integral_constant_like.hpp @@ -0,0 +1,157 @@ +//@HEADER +// ************************************************************************ +// +// Kokkos v. 4.0 +// Copyright (2022) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). +// +// Under the terms of Contract DE-NA0003525 with NTESS, +// the U.S. Government retains certain rights in this software. +// +// Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions. +// See https://kokkos.org/LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//@HEADER + +#pragma once + +#include "../__p0009_bits/utility.hpp" +#include +#if defined(__cpp_lib_concepts) +# include +#endif // __cpp_lib_concepts + +// ============================================================ +// equality_comparable back-port (used only by integral_constant_like) +// ============================================================ + +#if defined(__cpp_lib_concepts) + +namespace MDSPAN_IMPL_STANDARD_NAMESPACE { + namespace detail { + template + struct is_equality_comparable : std::bool_constant> {}; + + template + struct is_equality_comparable_with : std::bool_constant> {}; + } // namespace detail +} // namespace MDSPAN_IMPL_STANDARD_NAMESPACE + +#else + +#include + +namespace MDSPAN_IMPL_STANDARD_NAMESPACE { +namespace detail { + + template + struct is_equality_comparable : std::false_type {}; + + template + struct is_equality_comparable< + T, + std::void_t< + decltype(std::declval() == std::declval()), + decltype(std::declval() != std::declval()) + > + > : std::bool_constant< + std::is_convertible_v< + decltype(std::declval() == std::declval()), + bool + > && + std::is_convertible_v< + decltype(std::declval() != std::declval()), + bool + > + > {}; + + template + struct is_equality_comparable_with : std::false_type {}; + + template + struct is_equality_comparable_with< + T, U, + std::void_t< + decltype(std::declval() == std::declval()), + decltype(std::declval() != std::declval()), + decltype(std::declval() == std::declval()), + decltype(std::declval() != std::declval()) + > + > : std::bool_constant< + is_equality_comparable::value && + is_equality_comparable::value && + std::is_convertible_v< + decltype(std::declval() == std::declval()), + bool + > && + std::is_convertible_v< + decltype(std::declval() != std::declval()), + bool + > && + std::is_convertible_v< + decltype(std::declval() == std::declval()), + bool + > && + std::is_convertible_v< + decltype(std::declval() != std::declval()), + bool + > + > {}; + +} // namespace detail +} // namespace MDSPAN_IMPL_STANDARD_NAMESPACE + +#endif // defined(__cpp_lib_concepts) + +// ============================================================ +// integral_constant_like concept / trait +// ============================================================ + +#if defined(__cpp_lib_concepts) + +namespace MDSPAN_IMPL_STANDARD_NAMESPACE { + namespace detail { + + template + concept integral_constant_like = + std::is_integral_v> && + !std::is_same_v> && + std::convertible_to && + std::equality_comparable_with && + std::bool_constant::value && + std::bool_constant(T()) == T::value>::value; + + template + constexpr bool is_integral_constant_like_v = integral_constant_like; + + } // namespace detail +} // namespace MDSPAN_IMPL_STANDARD_NAMESPACE + +#else + +namespace MDSPAN_IMPL_STANDARD_NAMESPACE { + namespace detail { + + template + struct is_integral_constant_like_impl : std::false_type {}; + + template + struct is_integral_constant_like_impl> : + std::bool_constant< + std::is_integral_v> && + ! std::is_same_v> && + std::is_convertible_v && + is_equality_comparable_with::value && + std::bool_constant::value && + std::bool_constant(T()) == T::value>::value + > + {}; + + template + constexpr bool is_integral_constant_like_v = is_integral_constant_like_impl::value; + + } // namespace detail +} // namespace MDSPAN_IMPL_STANDARD_NAMESPACE + +#endif // __cpp_lib_concepts diff --git a/include/experimental/__p2630_bits/strided_slice.hpp b/include/experimental/__p2630_bits/strided_slice.hpp index 7f4a0188..f1fa6d1a 100644 --- a/include/experimental/__p2630_bits/strided_slice.hpp +++ b/include/experimental/__p2630_bits/strided_slice.hpp @@ -17,17 +17,36 @@ #pragma once +#include "../__p0009_bits/config.hpp" +#include "constant_wrapper.hpp" +#include "integral_constant_like.hpp" + #include namespace MDSPAN_IMPL_STANDARD_NAMESPACE { namespace detail { + template + struct is_signed_or_unsigned_integral_constant_like : std::false_type {}; + template - struct mdspan_is_integral_constant: std::false_type {}; + struct is_signed_or_unsigned_integral_constant_like< + T, std::enable_if_t> + > : std::bool_constant< + std::is_integral_v> && + ! std::is_same_v> + > + {}; - template - struct mdspan_is_integral_constant>: std::true_type {}; -} + template + constexpr bool is_signed_or_unsigned_integral_constant_like_v = + is_signed_or_unsigned_integral_constant_like::value; + + template + constexpr bool mdspan_is_index_like_v = + (std::is_integral_v && ! std::is_same_v) || + is_signed_or_unsigned_integral_constant_like_v; +} // namespace detail // Slice Specifier allowing for strides and compile time extent template @@ -40,9 +59,9 @@ struct strided_slice { MDSPAN_IMPL_NO_UNIQUE_ADDRESS ExtentType extent{}; MDSPAN_IMPL_NO_UNIQUE_ADDRESS StrideType stride{}; - static_assert(std::is_integral_v || detail::mdspan_is_integral_constant::value); - static_assert(std::is_integral_v || detail::mdspan_is_integral_constant::value); - static_assert(std::is_integral_v || detail::mdspan_is_integral_constant::value); + static_assert(detail::mdspan_is_index_like_v); + static_assert(detail::mdspan_is_index_like_v); + static_assert(detail::mdspan_is_index_like_v); }; } // MDSPAN_IMPL_STANDARD_NAMESPACE diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index c3abd883..1693ac65 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -113,3 +113,4 @@ endif() endif() mdspan_add_test(test_constant_wrapper) +mdspan_add_test(test_strided_slice) diff --git a/tests/test_strided_slice.cpp b/tests/test_strided_slice.cpp new file mode 100644 index 00000000..f16a20e0 --- /dev/null +++ b/tests/test_strided_slice.cpp @@ -0,0 +1,94 @@ +//@HEADER +// ************************************************************************ +// +// Kokkos v. 4.0 +// Copyright (2022) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). +// +// Under the terms of Contract DE-NA0003525 with NTESS, +// the U.S. Government retains certain rights in this software. +// +// Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions. +// See https://kokkos.org/LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//@HEADER +#include +#include + +#include + +namespace { + +template +void test_strided_slice(OffsetType offset, ExtentType extent, StrideType stride) +{ + // Some compilers are bad at CTAD for aggregates. + Kokkos::strided_slice s{offset, extent, stride}; + + static_assert(std::is_same_v>); + auto offset2 = s.offset; + static_assert(std::is_same_v); + auto extent2 = s.extent; + static_assert(std::is_same_v); + auto stride2 = s.stride; + static_assert(std::is_same_v); + + ASSERT_EQ(offset2, offset); + ASSERT_EQ(extent2, extent); + ASSERT_EQ(stride2, stride); +} + +template +constexpr auto IC = std::integral_constant{}; + +MDSPAN_TEMPLATE_REQUIRES( + class T, + T Value, + /* requires */ ( + std::is_integral_v && ! std::is_same_v + ) +) +struct my_integral_constant { + static constexpr T value = Value; + constexpr operator T () const { return value; } +}; + +template +constexpr auto IC2 = my_integral_constant{}; + +static_assert( + std::is_convertible_v< + my_integral_constant, + decltype(my_integral_constant::value)>); + +static_assert( + Kokkos::detail::is_equality_comparable_with< + my_integral_constant, + decltype(my_integral_constant::value)>::value); + +static_assert( + Kokkos::detail::is_integral_constant_like_v< + my_integral_constant + >); + +TEST(StridedSlice, WellFormed) { + test_strided_slice(int(1), unsigned(10), long(3)); + test_strided_slice((signed char)(1), (unsigned short)(10), (unsigned long long)(3)); + + test_strided_slice(IC, unsigned(10), long(3)); + test_strided_slice(int(1), IC, long(3)); + test_strided_slice(int(1), unsigned(10), IC); + + using MDSPAN_IMPL_STANDARD_NAMESPACE::detail::cw; + + test_strided_slice(cw<1>, unsigned(10), long(3)); + test_strided_slice(int(1), cw, long(3)); + test_strided_slice(int(1), unsigned(10), cw); + + test_strided_slice(IC2, unsigned(10), long(3)); + test_strided_slice(int(1), IC2, long(3)); + test_strided_slice(int(1), unsigned(10), IC2); +} + +} // namespace (anonymous)