//@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 #include "strided_slice.hpp" #include "../__p0009_bits/utility.hpp" namespace MDSPAN_IMPL_STANDARD_NAMESPACE { namespace detail { // Mapping from submapping ranks to srcmapping ranks // InvMapRank is an index_sequence, which we build recursively // to contain the mapped indices. // end of recursion specialization containing the final index_sequence template MDSPAN_INLINE_FUNCTION constexpr auto inv_map_rank(std::integral_constant, std::index_sequence) { return std::index_sequence(); } // specialization reducing rank by one (i.e., integral slice specifier) template MDSPAN_INLINE_FUNCTION constexpr auto inv_map_rank(std::integral_constant, std::index_sequence, Slice, SliceSpecifiers... slices) { using next_idx_seq_t = std::conditional_t, std::index_sequence, std::index_sequence>; return inv_map_rank(std::integral_constant(), next_idx_seq_t(), slices...); } // Helper for identifying strided_slice template struct is_strided_slice : std::false_type {}; template struct is_strided_slice< strided_slice> : std::true_type {}; // Helper for identifying valid pair like things template struct index_pair_like : std::false_type {}; template struct index_pair_like, IndexType> { static constexpr bool value = std::is_convertible_v && std::is_convertible_v; }; template struct index_pair_like, IndexType> { static constexpr bool value = std::is_convertible_v && std::is_convertible_v; }; template struct index_pair_like, IndexType> { static constexpr bool value = std::is_convertible_v && std::is_convertible_v; }; template struct index_pair_like, IndexType> { static constexpr bool value = std::is_convertible_v; }; template struct index_pair_like, IndexType> { static constexpr bool value = std::is_convertible_v; }; // first_of(slice): getting begin of slice specifier range MDSPAN_TEMPLATE_REQUIRES( class Integral, /* requires */(std::is_convertible_v) ) MDSPAN_INLINE_FUNCTION constexpr Integral first_of(const Integral &i) { return i; } template MDSPAN_INLINE_FUNCTION constexpr Integral first_of(const std::integral_constant&) { return integral_constant(); } MDSPAN_INLINE_FUNCTION constexpr integral_constant first_of(const ::MDSPAN_IMPL_STANDARD_NAMESPACE::full_extent_t &) { return integral_constant(); } MDSPAN_TEMPLATE_REQUIRES( class Slice, /* requires */(index_pair_like::value) ) MDSPAN_INLINE_FUNCTION constexpr auto first_of(const Slice &i) { return get<0>(i); } MDSPAN_TEMPLATE_REQUIRES( class IdxT1, class IdxT2, /* requires */ (index_pair_like, size_t>::value) ) constexpr auto first_of(const std::tuple& i) { return get<0>(i); } MDSPAN_TEMPLATE_REQUIRES( class IdxT1, class IdxT2, /* requires */ (index_pair_like, size_t>::value) ) MDSPAN_INLINE_FUNCTION constexpr auto first_of(const std::pair& i) { return i.first; } template MDSPAN_INLINE_FUNCTION constexpr auto first_of(const std::complex &i) { return i.real(); } template MDSPAN_INLINE_FUNCTION constexpr OffsetType first_of(const strided_slice &r) { return r.offset; } // last_of(slice): getting end of slice specifier range // We need however not just the slice but also the extents // of the original view and which rank from the extents. // This is needed in the case of slice being full_extent_t. MDSPAN_TEMPLATE_REQUIRES( size_t k, class Extents, class Integral, /* requires */(std::is_convertible_v) ) MDSPAN_INLINE_FUNCTION constexpr Integral last_of(std::integral_constant, const Extents &, const Integral &i) { return i; } MDSPAN_TEMPLATE_REQUIRES( size_t k, class Extents, class Slice, /* requires */(index_pair_like::value) ) MDSPAN_INLINE_FUNCTION constexpr auto last_of(std::integral_constant, const Extents &, const Slice &i) { return get<1>(i); } MDSPAN_TEMPLATE_REQUIRES( size_t k, class Extents, class IdxT1, class IdxT2, /* requires */ (index_pair_like, size_t>::value) ) constexpr auto last_of(std::integral_constant, const Extents &, const std::tuple& i) { return get<1>(i); } MDSPAN_TEMPLATE_REQUIRES( size_t k, class Extents, class IdxT1, class IdxT2, /* requires */ (index_pair_like, size_t>::value) ) MDSPAN_INLINE_FUNCTION constexpr auto last_of(std::integral_constant, const Extents &, const std::pair& i) { return i.second; } template MDSPAN_INLINE_FUNCTION constexpr auto last_of(std::integral_constant, const Extents &, const std::complex &i) { return i.imag(); } // Suppress spurious warning with NVCC about no return statement. // This is a known issue in NVCC and NVC++ // Depending on the CUDA and GCC version we need both the builtin // and the diagnostic push. I tried really hard to find something shorter // but no luck ... #if defined __NVCC__ #ifdef __NVCC_DIAG_PRAGMA_SUPPORT__ #pragma nv_diagnostic push #pragma nv_diag_suppress = implicit_return_from_non_void_function #else #ifdef __CUDA_ARCH__ #pragma diagnostic push #pragma diag_suppress implicit_return_from_non_void_function #endif #endif #elif defined __NVCOMPILER #pragma diagnostic push #pragma diag_suppress = implicit_return_from_non_void_function #endif template MDSPAN_INLINE_FUNCTION constexpr auto last_of(std::integral_constant, const Extents &ext, ::MDSPAN_IMPL_STANDARD_NAMESPACE::full_extent_t) { if constexpr (Extents::static_extent(k) == dynamic_extent) { return ext.extent(k); } else { return integral_constant(); } #if defined(__NVCC__) && !defined(__CUDA_ARCH__) && defined(__GNUC__) // Even with CUDA_ARCH protection this thing warns about calling host function __builtin_unreachable(); #endif } #if defined __NVCC__ #ifdef __NVCC_DIAG_PRAGMA_SUPPORT__ #pragma nv_diagnostic pop #else #ifdef __CUDA_ARCH__ #pragma diagnostic pop #endif #endif #elif defined __NVCOMPILER #pragma diagnostic pop #endif template MDSPAN_INLINE_FUNCTION constexpr OffsetType last_of(std::integral_constant, const Extents &, const strided_slice &r) { return r.extent; } // get stride of slices template MDSPAN_INLINE_FUNCTION constexpr auto stride_of(const T &) { return integral_constant(); } template MDSPAN_INLINE_FUNCTION constexpr auto stride_of(const strided_slice &r) { return r.stride; } // divide which can deal with integral constant preservation template MDSPAN_INLINE_FUNCTION constexpr auto divide(const T0 &v0, const T1 &v1) { return IndexT(v0) / IndexT(v1); } template MDSPAN_INLINE_FUNCTION constexpr auto divide(const std::integral_constant &, const std::integral_constant &) { // cutting short division by zero // this is used for strided_slice with zero extent/stride return integral_constant(); } // multiply which can deal with integral constant preservation template MDSPAN_INLINE_FUNCTION constexpr auto multiply(const T0 &v0, const T1 &v1) { return IndexT(v0) * IndexT(v1); } template MDSPAN_INLINE_FUNCTION constexpr auto multiply(const std::integral_constant &, const std::integral_constant &) { return integral_constant(); } // compute new static extent from range, preserving static knowledge template struct StaticExtentFromRange { constexpr static size_t value = dynamic_extent; }; template struct StaticExtentFromRange, std::integral_constant> { constexpr static size_t value = val1 - val0; }; template struct StaticExtentFromRange, integral_constant> { constexpr static size_t value = val1 - val0; }; // compute new static extent from strided_slice, preserving static // knowledge template struct StaticExtentFromStridedRange { constexpr static size_t value = dynamic_extent; }; template struct StaticExtentFromStridedRange, std::integral_constant> { constexpr static size_t value = val0 > 0 ? 1 + (val0 - 1) / val1 : 0; }; template struct StaticExtentFromStridedRange, integral_constant> { constexpr static size_t value = val0 > 0 ? 1 + (val0 - 1) / val1 : 0; }; // creates new extents through recursive calls to next_extent member function // next_extent has different overloads for different types of stride specifiers template struct extents_constructor { MDSPAN_TEMPLATE_REQUIRES( class Slice, class... SlicesAndExtents, /* requires */(!std::is_convertible_v && !is_strided_slice::value) ) MDSPAN_INLINE_FUNCTION constexpr static auto next_extent(const Extents &ext, const Slice &sl, SlicesAndExtents... slices_and_extents) { constexpr size_t new_static_extent = StaticExtentFromRange< decltype(first_of(std::declval())), decltype(last_of(std::integral_constant(), std::declval(), std::declval()))>::value; using next_t = extents_constructor; using index_t = typename Extents::index_type; return next_t::next_extent( ext, slices_and_extents..., index_t(last_of(std::integral_constant(), ext, sl)) - index_t(first_of(sl))); } MDSPAN_TEMPLATE_REQUIRES( class Slice, class... SlicesAndExtents, /* requires */ (std::is_convertible_v) ) MDSPAN_INLINE_FUNCTION constexpr static auto next_extent(const Extents &ext, const Slice &, SlicesAndExtents... slices_and_extents) { using next_t = extents_constructor; return next_t::next_extent(ext, slices_and_extents...); } template MDSPAN_INLINE_FUNCTION constexpr static auto next_extent(const Extents &ext, const strided_slice &r, SlicesAndExtents... slices_and_extents) { using index_t = typename Extents::index_type; using new_static_extent_t = StaticExtentFromStridedRange; if constexpr (new_static_extent_t::value == dynamic_extent) { using next_t = extents_constructor; return next_t::next_extent( ext, slices_and_extents..., r.extent > 0 ? 1 + divide(r.extent - 1, r.stride) : 0); } else { constexpr size_t new_static_extent = new_static_extent_t::value; using next_t = extents_constructor; return next_t::next_extent( ext, slices_and_extents..., index_t(divide(ExtentType(), StrideType()))); } } }; template struct extents_constructor<0, Extents, NewStaticExtents...> { template MDSPAN_INLINE_FUNCTION constexpr static auto next_extent(const Extents &, NewExtents... new_exts) { return extents( new_exts...); } }; } // namespace detail // submdspan_extents creates new extents given src extents and submdspan slice // specifiers template MDSPAN_INLINE_FUNCTION constexpr auto submdspan_extents(const extents &src_exts, SliceSpecifiers... slices) { using ext_t = extents; return detail::extents_constructor::next_extent( src_exts, slices...); } } // namespace MDSPAN_IMPL_STANDARD_NAMESPACE