/* //@HEADER // ************************************************************************ // // Kokkos v. 2.0 // Copyright (2019) Sandia Corporation // // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // 1. Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // // 2. Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // 3. Neither the name of the Corporation nor the names of the // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Questions? Contact Christian R. Trott (crtrott@sandia.gov) // // ************************************************************************ //@HEADER */ #ifndef _LIBCUDACXX___MDSPAN_EXTENTS_HPP #define _LIBCUDACXX___MDSPAN_EXTENTS_HPP #include #if defined(_CCCL_IMPLICIT_SYSTEM_HEADER_GCC) # pragma GCC system_header #elif defined(_CCCL_IMPLICIT_SYSTEM_HEADER_CLANG) # pragma clang system_header #elif defined(_CCCL_IMPLICIT_SYSTEM_HEADER_MSVC) # pragma system_header #endif // no system header #include #ifdef _CCCL_HAS_NO_ATTRIBUTE_NO_UNIQUE_ADDRESS # include #endif // _CCCL_HAS_NO_ATTRIBUTE_NO_UNIQUE_ADDRESS #include #include #include #include #include #include #include #include #include #include #include _CCCL_PUSH_MACROS _LIBCUDACXX_BEGIN_NAMESPACE_STD #if _CCCL_STD_VER > 2011 namespace __detail { template struct __count_dynamic_extents; template struct __count_dynamic_extents<_Ep, _Extents...> { static constexpr size_t val = (_Ep == dynamic_extent ? 1 : 0) + __count_dynamic_extents<_Extents...>::val; }; template <> struct __count_dynamic_extents<> { static constexpr size_t val = 0; }; template _CCCL_HOST_DEVICE static constexpr false_type __check_compatible_extents( false_type, _CUDA_VSTD::integer_sequence, _CUDA_VSTD::integer_sequence) noexcept { return {}; } // This helper prevents ICE's on MSVC. template struct __compare_extent_compatible : integral_constant {}; template static integral_constant::value) /* && ... */ )> _CCCL_HOST_DEVICE __check_compatible_extents(true_type, _CUDA_VSTD::integer_sequence, _CUDA_VSTD::integer_sequence) noexcept { return {}; } struct __extents_tag {}; } // end namespace __detail template class extents # ifdef _CCCL_HAS_NO_ATTRIBUTE_NO_UNIQUE_ADDRESS : private __detail::__no_unique_address_emulation< __detail::__partially_static_sizes_tagged<__detail::__extents_tag, _ThisIndexType, size_t, _Extents...>> # endif { public: using rank_type = size_t; using index_type = _ThisIndexType; using size_type = make_unsigned_t; // internal typedefs which for technical reasons are public using __storage_t = __detail::__partially_static_sizes_tagged<__detail::__extents_tag, index_type, size_t, _Extents...>; # ifndef _CCCL_HAS_NO_ATTRIBUTE_NO_UNIQUE_ADDRESS _CCCL_NO_UNIQUE_ADDRESS __storage_t __storage_; # else using __base_t = __detail::__no_unique_address_emulation<__storage_t>; # endif // private members dealing with the way we internally store dynamic extents private: __MDSPAN_FORCE_INLINE_FUNCTION constexpr __storage_t& __storage() noexcept { # ifndef _CCCL_HAS_NO_ATTRIBUTE_NO_UNIQUE_ADDRESS return __storage_; # else return this->__base_t::__ref(); # endif } __MDSPAN_FORCE_INLINE_FUNCTION constexpr __storage_t const& __storage() const noexcept { # ifndef _CCCL_HAS_NO_ATTRIBUTE_NO_UNIQUE_ADDRESS return __storage_; # else return this->__base_t::__ref(); # endif } template __MDSPAN_FORCE_INLINE_FUNCTION static constexpr index_type _static_extent_impl(size_t __n, _CUDA_VSTD::integer_sequence) noexcept { return __MDSPAN_FOLD_PLUS_RIGHT(((_Idxs == __n) ? _Extents : 0), /* + ... + */ 0); } template friend class extents; template __MDSPAN_INLINE_FUNCTION constexpr bool _eq_impl(_CUDA_VSTD::extents<_OtherIndexType, _OtherExtents...>, false_type, _CUDA_VSTD::index_sequence<_Idxs...>) const noexcept { return false; } template __MDSPAN_INLINE_FUNCTION constexpr bool _eq_impl(_CUDA_VSTD::extents<_OtherIndexType, _OtherExtents...> __other, true_type, _CUDA_VSTD::index_sequence<_Idxs...>) const noexcept { return __MDSPAN_FOLD_AND( (__storage().template __get_n<_Idxs>() == __other.__storage().template __get_n<_Idxs>()) /* && ... */ ); } template __MDSPAN_INLINE_FUNCTION constexpr bool _not_eq_impl(_CUDA_VSTD::extents<_OtherIndexType, _OtherExtents...>, false_type, _CUDA_VSTD::index_sequence<_Idxs...>) const noexcept { return true; } template __MDSPAN_INLINE_FUNCTION constexpr bool _not_eq_impl(_CUDA_VSTD::extents<_OtherIndexType, _OtherExtents...> __other, true_type, _CUDA_VSTD::index_sequence<_Idxs...>) const noexcept { return __MDSPAN_FOLD_OR( (__storage().template __get_n<_Idxs>() != __other.__storage().template __get_n<_Idxs>()) /* || ... */ ); } # ifdef _CCCL_HAS_NO_ATTRIBUTE_NO_UNIQUE_ADDRESS __MDSPAN_INLINE_FUNCTION constexpr explicit extents(__base_t&& __b) noexcept : __base_t(_CUDA_VSTD::move(__b)) {} # endif // public interface: public: /* Defined above for use in the private code using rank_type = size_t; using index_type = _ThisIndexType; */ __MDSPAN_INLINE_FUNCTION static constexpr rank_type rank() noexcept { return sizeof...(_Extents); } __MDSPAN_INLINE_FUNCTION static constexpr rank_type rank_dynamic() noexcept { return __MDSPAN_FOLD_PLUS_RIGHT((rank_type(_Extents == dynamic_extent)), /* + ... + */ 0); } //-------------------------------------------------------------------------------- // Constructors, Destructors, and Assignment // Default constructor __MDSPAN_INLINE_FUNCTION_DEFAULTED constexpr extents() noexcept = default; // Converting constructor __MDSPAN_TEMPLATE_REQUIRES( class _OtherIndexType, size_t... _OtherExtents, /* requires */ ( /* multi-stage check to protect from invalid pack expansion when sizes don't match? */ decltype(__detail::__check_compatible_extents( integral_constant{}, _CUDA_VSTD::integer_sequence{}, _CUDA_VSTD::integer_sequence{}))::value)) __MDSPAN_INLINE_FUNCTION __MDSPAN_CONDITIONAL_EXPLICIT( (((_Extents != dynamic_extent) && (_OtherExtents == dynamic_extent)) || ...) || (_CUDA_VSTD::numeric_limits::max() < _CUDA_VSTD::numeric_limits<_OtherIndexType>::max())) constexpr extents(const extents<_OtherIndexType, _OtherExtents...>& __other) noexcept # ifndef _CCCL_HAS_NO_ATTRIBUTE_NO_UNIQUE_ADDRESS : __storage_{ # else : __base_t(__base_t { __storage_t { # endif __other.__storage().__enable_psa_conversion() # ifndef _CCCL_HAS_NO_ATTRIBUTE_NO_UNIQUE_ADDRESS } # else } }) # endif { /* TODO: precondition check * __other.extent(r) equals Er for each r for which Er is a static extent, and * either * - sizeof...(_OtherExtents) is zero, or * - __other.extent(r) is a representable value of type index_type for all rank index r of __other */ } # ifdef __NVCC__ __MDSPAN_TEMPLATE_REQUIRES( class... _Integral, /* requires */ ( // TODO: check whether the other version works with newest NVCC, doesn't with 11.4 // NVCC seems to pick up rank_dynamic from the wrong extents type??? __MDSPAN_FOLD_AND(_CCCL_TRAIT(_CUDA_VSTD::is_convertible, _Integral, index_type) /* && ... */) && __MDSPAN_FOLD_AND(_CCCL_TRAIT(_CUDA_VSTD::is_nothrow_constructible, index_type, _Integral) /* && ... */) && // NVCC chokes on the fold thingy here so wrote the workaround ((sizeof...(_Integral) == __detail::__count_dynamic_extents<_Extents...>::val) || (sizeof...(_Integral) == sizeof...(_Extents))))) # else __MDSPAN_TEMPLATE_REQUIRES( class... _Integral, /* requires */ ( __MDSPAN_FOLD_AND(_CCCL_TRAIT(_CUDA_VSTD::is_convertible, _Integral, index_type) /* && ... */) && __MDSPAN_FOLD_AND(_CCCL_TRAIT(_CUDA_VSTD::is_nothrow_constructible, index_type, _Integral) /* && ... */) && ((sizeof...(_Integral) == rank_dynamic()) || (sizeof...(_Integral) == rank())))) # endif __MDSPAN_INLINE_FUNCTION explicit constexpr extents(_Integral... __exts) noexcept # ifndef _CCCL_HAS_NO_ATTRIBUTE_NO_UNIQUE_ADDRESS : __storage_{ # else : __base_t(__base_t { typename __base_t::__stored_type { # endif _CUDA_VSTD::conditional_t(), static_cast(__exts)... # ifndef _CCCL_HAS_NO_ATTRIBUTE_NO_UNIQUE_ADDRESS } # else } }) # endif { /* TODO: precondition check * If sizeof...(_IndexTypes) != rank_dynamic() is true, exts_arr[r] equals Er for each r for which Er is a static * extent, and either * - sizeof...(__exts) == 0 is true, or * - each element of __exts is nonnegative and is a representable value of type index_type. */ } // TODO: check whether this works with newest NVCC, doesn't with 11.4 # ifdef __NVCC__ // NVCC seems to pick up rank_dynamic from the wrong extents type??? // NVCC chokes on the fold thingy here so wrote the workaround __MDSPAN_TEMPLATE_REQUIRES( class _IndexType, size_t _Np, /* requires */ (_CCCL_TRAIT(_CUDA_VSTD::is_convertible, _IndexType, index_type) && _CCCL_TRAIT(_CUDA_VSTD::is_nothrow_constructible, index_type, _IndexType) && ((_Np == __detail::__count_dynamic_extents<_Extents...>::val) || (_Np == sizeof...(_Extents))))) # else __MDSPAN_TEMPLATE_REQUIRES( class _IndexType, size_t _Np, /* requires */ (_CCCL_TRAIT(_CUDA_VSTD::is_convertible, _IndexType, index_type) && _CCCL_TRAIT(_CUDA_VSTD::is_nothrow_constructible, index_type, _IndexType) && (_Np == rank() || _Np == rank_dynamic()))) # endif __MDSPAN_CONDITIONAL_EXPLICIT(_Np != rank_dynamic()) __MDSPAN_INLINE_FUNCTION constexpr extents(_CUDA_VSTD::array<_IndexType, _Np> const& __exts) noexcept # ifndef _CCCL_HAS_NO_ATTRIBUTE_NO_UNIQUE_ADDRESS : __storage_{ # else : __base_t(__base_t { typename __base_t::__stored_type { # endif _CUDA_VSTD::conditional_t<_Np == rank_dynamic(), __detail::__construct_psa_from_dynamic_exts_array_tag_t<0>, __detail::__construct_psa_from_all_exts_array_tag_t>(), _CUDA_VSTD::array<_IndexType, _Np>{__exts} # ifndef _CCCL_HAS_NO_ATTRIBUTE_NO_UNIQUE_ADDRESS } # else } }) # endif { /* TODO: precondition check * If _Np != rank_dynamic() is true, __exts[r] equals Er for each r for which Er is a static extent, and * either * - _Np is zero, or * - __exts[r] is nonnegative and is a representable value of type index_type for all rank index r */ } // TODO: check whether the below works with newest NVCC, doesn't with 11.4 # ifdef __NVCC__ // NVCC seems to pick up rank_dynamic from the wrong extents type??? // NVCC chokes on the fold thingy here so wrote the workaround __MDSPAN_TEMPLATE_REQUIRES( class _IndexType, size_t _Np, /* requires */ (_CCCL_TRAIT(_CUDA_VSTD::is_convertible, _IndexType, index_type) && _CCCL_TRAIT(_CUDA_VSTD::is_nothrow_constructible, index_type, _IndexType) && ((_Np == __detail::__count_dynamic_extents<_Extents...>::val) || (_Np == sizeof...(_Extents))))) # else __MDSPAN_TEMPLATE_REQUIRES( class _IndexType, size_t _Np, /* requires */ (_CCCL_TRAIT(_CUDA_VSTD::is_convertible, _IndexType, index_type) && _CCCL_TRAIT(_CUDA_VSTD::is_nothrow_constructible, index_type, _IndexType) && (_Np == rank() || _Np == rank_dynamic()))) # endif __MDSPAN_CONDITIONAL_EXPLICIT(_Np != rank_dynamic()) __MDSPAN_INLINE_FUNCTION constexpr extents(_CUDA_VSTD::span<_IndexType, _Np> __exts) noexcept # ifndef _CCCL_HAS_NO_ATTRIBUTE_NO_UNIQUE_ADDRESS : __storage_{ # else : __base_t(__base_t { typename __base_t::__stored_type { # endif _CUDA_VSTD::conditional_t<_Np == rank_dynamic(), __detail::__construct_psa_from_dynamic_exts_array_tag_t<0>, __detail::__construct_psa_from_all_exts_array_tag_t>(), __exts # ifndef _CCCL_HAS_NO_ATTRIBUTE_NO_UNIQUE_ADDRESS } # else } }) # endif { /* TODO: precondition check * If _Np != rank_dynamic() is true, __exts[r] equals Er for each r for which Er is a static extent, and * either * - _Np is zero, or * - __exts[r] is nonnegative and is a representable value of type index_type for all rank index r */ } // Need this constructor for some submdspan implementation stuff // for the layout_stride case where I use an extents object for strides __MDSPAN_INLINE_FUNCTION constexpr explicit extents(__storage_t const& __sto) noexcept # ifndef _CCCL_HAS_NO_ATTRIBUTE_NO_UNIQUE_ADDRESS : __storage_{ # else : __base_t(__base_t { # endif __sto # ifndef _CCCL_HAS_NO_ATTRIBUTE_NO_UNIQUE_ADDRESS } # else }) # endif {} //-------------------------------------------------------------------------------- __MDSPAN_INLINE_FUNCTION static constexpr size_t static_extent(size_t __n) noexcept { // Can't do assert here since that breaks true constexpr ness // assert(__n{}); } __MDSPAN_INLINE_FUNCTION constexpr index_type extent(size_t __n) const noexcept { // Can't do assert here since that breaks true constexpr ness // assert(__n __MDSPAN_INLINE_FUNCTION friend constexpr bool operator==(extents const& lhs, extents<_OtherIndexType, _RHS...> const& __rhs) noexcept { return lhs._eq_impl(__rhs, integral_constant{}, _CUDA_VSTD::make_index_sequence{}); } # if !(__MDSPAN_HAS_CXX_20) template __MDSPAN_INLINE_FUNCTION friend constexpr bool operator!=(extents const& lhs, extents<_OtherIndexType, _RHS...> const& __rhs) noexcept { return lhs._not_eq_impl(__rhs, integral_constant{}, _CUDA_VSTD::make_index_sequence{}); } # endif // End of public interface public: // (but not really) __MDSPAN_INLINE_FUNCTION static constexpr extents __make_extents_impl(__detail::__partially_static_sizes&& __bs) noexcept { // This effectively amounts to a sideways cast that can be done in a constexpr // context, but we have to do it to handle the case where the extents and the // strides could accidentally end up with the same types in their hierarchies // somehow (which would cause layout_stride::mapping to not be standard_layout) return extents( # ifdef _CCCL_HAS_NO_ATTRIBUTE_NO_UNIQUE_ADDRESS __base_t{ # endif _CUDA_VSTD::move(__bs.template __with_tag<__detail::__extents_tag>()) # ifdef _CCCL_HAS_NO_ATTRIBUTE_NO_UNIQUE_ADDRESS } # endif ); } template __MDSPAN_FORCE_INLINE_FUNCTION constexpr index_type __extent() const noexcept { return __storage().template __get_n<_Np>(); } template __MDSPAN_INLINE_FUNCTION static constexpr index_type __static_extent() noexcept { return __storage_t::template __get_static_n<_Np, _Default>(); } }; namespace __detail { template > struct __make_dextents; template struct __make_dextents<_IndexType, _Rank, _CUDA_VSTD::extents<_IndexType, _ExtentsPack...>> { using type = typename __make_dextents<_IndexType, _Rank - 1, _CUDA_VSTD::extents<_IndexType, _CUDA_VSTD::dynamic_extent, _ExtentsPack...>>::type; }; template struct __make_dextents<_IndexType, 0, _CUDA_VSTD::extents<_IndexType, _ExtentsPack...>> { using type = _CUDA_VSTD::extents<_IndexType, _ExtentsPack...>; }; } // end namespace __detail template using dextents = typename __detail::__make_dextents<_IndexType, _Rank>::type; # if defined(__MDSPAN_USE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION) template _CCCL_HOST_DEVICE extents(_IndexTypes...) // Workaround for nvcc //-> extents()...>; // Adding "(void)" so that clang doesn't complain this is unused ->extents; # endif namespace __detail { template struct __is_extents : false_type {}; template struct __is_extents<_CUDA_VSTD::extents<_IndexType, _ExtentsPack...>> : true_type {}; template static constexpr bool __is_extents_v = __is_extents<_Tp>::value; template struct __extents_to_partially_static_sizes; template struct __extents_to_partially_static_sizes<_CUDA_VSTD::extents<_IndexType, _ExtentsPack...>> { using type = __detail::__partially_static_sizes::index_type, size_t, _ExtentsPack...>; }; template using __extents_to_partially_static_sizes_t = typename __extents_to_partially_static_sizes<_Extents>::type; } // end namespace __detail #endif // _CCCL_STD_VER > 2011 _LIBCUDACXX_END_NAMESPACE_STD _CCCL_POP_MACROS #endif // _LIBCUDACXX___MDSPAN_EXTENTS_HPP