[INFRA] Import NVIDIA/CCCL upstream as optimization reference library

CCCL (CUDA C++ Core Libraries) provides:
- CUB: device/block/warp-level GPU primitives (reduce, scan, sort, topk)
- Thrust: high-level parallel algorithms (transform_reduce, sort, scan)
- libcudacxx: CUDA C++ standard library (atomics, barriers, memory)
- cudax: experimental features (memory resources, allocators)
- Tuning policies: per-SM hardware-specific algorithm parameters

Competition optimization vectors mapped to CCCL:
- Output TPS (83% weight): warp_reduce, block_reduce, device_topk
- Input TPS (14% weight): device_scan, block_load, prefetch
- Cache TPS (3% weight): prefix caching strategy patterns
- Memory (0.9 util): pooled/cached/buddy allocators

Source: https://github.com/NVIDIA/cccl (shallow clone, HEAD only)
License: Apache-2.0
This commit is contained in:
EngineX CI
2026-07-30 09:35:51 +00:00
parent b4d01f481e
commit 56fd68e7dd
8871 changed files with 1454674 additions and 0 deletions

View File

@@ -0,0 +1,96 @@
//@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
// SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES.
//
// ************************************************************************
//@HEADER
#ifndef _CUDA_STD___MDSPAN_ALIGNED_ACCESSOR_H
#define _CUDA_STD___MDSPAN_ALIGNED_ACCESSOR_H
#include <cuda/std/detail/__config>
#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 <cuda/__memory/is_valid_alignment.h>
#include <cuda/std/__concepts/concept_macros.h>
#include <cuda/std/__mdspan/default_accessor.h>
#include <cuda/std/__memory/assume_aligned.h>
#include <cuda/std/__type_traits/is_abstract.h>
#include <cuda/std/__type_traits/is_array.h>
#include <cuda/std/__type_traits/is_convertible.h>
#include <cuda/std/__type_traits/is_object.h>
#include <cuda/std/__cccl/prologue.h>
_CCCL_BEGIN_NAMESPACE_CUDA_STD
template <class _ElementType, size_t _ByteAlignment>
class aligned_accessor
{
public:
static constexpr auto byte_alignment = _ByteAlignment;
static_assert(::cuda::__is_valid_alignment<_ElementType>(byte_alignment), "Invalid _ByteAlignment for _ElementType");
static_assert(is_object_v<_ElementType> && !is_abstract_v<_ElementType> && !is_array_v<_ElementType>,
"_ElementType must be a complete object type that is neither an abstract class type nor an array "
"type.");
using offset_policy = default_accessor<_ElementType>;
using element_type = _ElementType;
using reference = _ElementType&;
using data_handle_type = _ElementType*;
_CCCL_HIDE_FROM_ABI aligned_accessor() noexcept = default;
_CCCL_TEMPLATE(class _OtherElementType, size_t _OtherByteAlignment)
_CCCL_REQUIRES(
is_convertible_v<_OtherElementType (*)[], element_type (*)[]> _CCCL_AND((_OtherByteAlignment >= byte_alignment)))
_CCCL_API constexpr aligned_accessor(aligned_accessor<_OtherElementType, _OtherByteAlignment>) noexcept {}
_CCCL_TEMPLATE(class _OtherElementType)
_CCCL_REQUIRES(is_convertible_v<_OtherElementType (*)[], element_type (*)[]>)
_CCCL_API constexpr explicit aligned_accessor(default_accessor<_OtherElementType>) noexcept {}
_CCCL_TEMPLATE(class _OtherElementType)
_CCCL_REQUIRES(is_convertible_v<_OtherElementType (*)[], element_type (*)[]>)
_CCCL_API constexpr operator default_accessor<_OtherElementType>() const noexcept
{
return {};
}
_CCCL_HOST_DEVICE_API constexpr reference access(data_handle_type __p, size_t __i) const noexcept
{
return ::cuda::std::assume_aligned<byte_alignment>(__p)[__i];
}
_CCCL_HOST_DEVICE_API constexpr typename offset_policy::data_handle_type
offset(data_handle_type __p, size_t __i) const noexcept
{
return ::cuda::std::assume_aligned<byte_alignment>(__p) + __i;
}
};
_CCCL_END_NAMESPACE_CUDA_STD
#include <cuda/std/__cccl/epilogue.h>
#endif // _CUDA_STD___MDSPAN_ALIGNED_ACCESSOR_H

View File

@@ -0,0 +1,141 @@
// -*- 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
// SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES.
//
// 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.
//
//===---------------------------------------------------------------------===//
#ifndef _CUDA_STD___MDSPAN_CONCEPTS_H
#define _CUDA_STD___MDSPAN_CONCEPTS_H
#include <cuda/std/detail/__config>
#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 <cuda/std/__concepts/concept_macros.h>
#include <cuda/std/__concepts/convertible_to.h>
#include <cuda/std/__concepts/copyable.h>
#include <cuda/std/__concepts/equality_comparable.h>
#include <cuda/std/__concepts/same_as.h>
#include <cuda/std/__fwd/mdspan.h>
#include <cuda/std/__tuple_dir/tuple_element.h>
#include <cuda/std/__tuple_dir/tuple_like.h>
#include <cuda/std/__type_traits/integral_constant.h>
#include <cuda/std/__type_traits/integral_constant_like.h>
#include <cuda/std/__type_traits/is_convertible.h>
#include <cuda/std/__type_traits/is_move_assignable.h>
#include <cuda/std/__type_traits/is_nothrow_constructible.h>
#include <cuda/std/__type_traits/is_nothrow_move_constructible.h>
#include <cuda/std/__type_traits/is_same.h>
#include <cuda/std/__type_traits/is_signed.h>
#include <cuda/std/__type_traits/is_swappable.h>
#include <cuda/std/__type_traits/is_unsigned.h>
#include <cuda/std/__type_traits/void_t.h>
#include <cuda/std/__utility/declval.h>
#include <cuda/std/__cccl/prologue.h>
_CCCL_BEGIN_NAMESPACE_CUDA_STD
namespace __mdspan_detail
{
// [mdspan.layout.stride.expo]/3
// [mdspan.layout.general]/2
template <class _Layout, class _Mapping>
inline constexpr bool __is_mapping_of =
is_same_v<typename _Layout::template mapping<typename _Mapping::extents_type>, _Mapping>;
// [mdspan.layout.reqmts]/1
template <class _Mapping>
_CCCL_CONCEPT __layout_mapping_req_type = _CCCL_REQUIRES_EXPR((_Mapping))(
requires(copyable<_Mapping>),
requires(equality_comparable<_Mapping>),
requires(is_nothrow_move_constructible_v<_Mapping>),
requires(is_move_assignable_v<_Mapping>),
requires(is_nothrow_swappable_v<_Mapping>));
// [mdspan.layout.reqmts]/2-4
template <class _Mapping>
_CCCL_CONCEPT __layout_mapping_req_types = _CCCL_REQUIRES_EXPR((_Mapping))(
requires(__is_cuda_std_extents_v<typename _Mapping::extents_type>),
requires(same_as<typename _Mapping::index_type, typename _Mapping::extents_type::index_type>),
requires(same_as<typename _Mapping::rank_type, typename _Mapping::extents_type::rank_type>),
requires(__is_mapping_of<typename _Mapping::layout_type, _Mapping>));
template <class _Mapping>
_CCCL_CONCEPT __layout_mapping_req_members = _CCCL_REQUIRES_EXPR((_Mapping), const _Mapping& __map)(
_Same_as(const typename _Mapping::extents_type&) __map.extents(),
_Same_as(typename _Mapping::index_type) __map.required_span_size(),
_Same_as(bool) __map.is_unique(),
_Same_as(bool) __map.is_exhaustive(),
_Same_as(bool) __map.is_strided());
template <class _Mapping>
_CCCL_CONCEPT __layout_mapping_req = _CCCL_REQUIRES_EXPR((_Mapping))(
requires(__layout_mapping_req_type<_Mapping>),
requires(__layout_mapping_req_types<_Mapping>),
requires(__layout_mapping_req_members<_Mapping>));
// [mdspan.layout.stride.expo]/4
// NOTE: integral_constant<bool, _Mapping::is_always_strided()>::value only checks that this is a constant expression
template <class _Mapping>
_CCCL_CONCEPT __layout_mapping_alike = _CCCL_REQUIRES_EXPR((_Mapping))(
requires(__is_mapping_of<typename _Mapping::layout_type, _Mapping>),
requires(__is_cuda_std_extents_v<typename _Mapping::extents_type>),
requires(same_as<bool, decltype(_Mapping::is_always_strided())>),
requires(same_as<bool, decltype(_Mapping::is_always_exhaustive())>),
requires(same_as<bool, decltype(_Mapping::is_always_unique())>),
(integral_constant<bool, _Mapping::is_always_strided()>::value),
(integral_constant<bool, _Mapping::is_always_exhaustive()>::value),
(integral_constant<bool, _Mapping::is_always_unique()>::value));
template <class _IndexType, class... _Indices>
_CCCL_CONCEPT __all_convertible_to_index_type =
(is_convertible_v<_Indices, _IndexType> && ... && true)
&& (is_nothrow_constructible_v<_IndexType, _Indices> && ... && true);
template <class _Extent, size_t _Size>
static constexpr bool __matches_dynamic_rank = (_Size == _Extent::rank_dynamic());
template <class _Extent, size_t _Size>
static constexpr bool __matches_static_rank = (_Size == _Extent::rank()) && (_Size != _Extent::rank_dynamic());
} // namespace __mdspan_detail
template <class _Tp, class _IndexType>
_CCCL_CONCEPT __index_pair_like = _CCCL_REQUIRES_EXPR((_Tp, _IndexType))(
requires(__pair_like<_Tp>),
requires(convertible_to<tuple_element_t<0, _Tp>, _IndexType>),
requires(convertible_to<tuple_element_t<1, _Tp>, _IndexType>));
// [mdspan.submdspan.strided.slice]/3
template <class _Tp>
_CCCL_CONCEPT __index_like = is_signed_v<_Tp> || is_unsigned_v<_Tp> || __integral_constant_like<_Tp>;
template <class _AccessorPolicy>
_CCCL_CONCEPT __has_detect_invalidity =
_CCCL_REQUIRES_EXPR((_AccessorPolicy), _AccessorPolicy __ap)(__ap.__detectably_invalid(
::cuda::std::declval<typename _AccessorPolicy::data_handle_type>(), ::cuda::std::declval<::cuda::std::size_t>()));
_CCCL_END_NAMESPACE_CUDA_STD
#include <cuda/std/__cccl/epilogue.h>
#endif // _CUDA_STD___MDSPAN_CONCEPTS_H

View File

@@ -0,0 +1,73 @@
// -*- 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
// SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES.
//
// 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.
//
//===---------------------------------------------------------------------===//
#ifndef _CUDA_STD___MDSPAN_DEFAULT_ACCESSOR_H
#define _CUDA_STD___MDSPAN_DEFAULT_ACCESSOR_H
#include <cuda/std/detail/__config>
#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 <cuda/std/__concepts/concept_macros.h>
#include <cuda/std/__fwd/mdspan.h>
#include <cuda/std/__type_traits/is_abstract.h>
#include <cuda/std/__type_traits/is_array.h>
#include <cuda/std/__type_traits/is_convertible.h>
#include <cuda/std/cstddef>
#include <cuda/std/__cccl/prologue.h>
_CCCL_BEGIN_NAMESPACE_CUDA_STD
template <class _ElementType>
struct default_accessor
{
static_assert(!is_array_v<_ElementType>, "default_accessor: template argument may not be an array type");
static_assert(!is_abstract_v<_ElementType>, "default_accessor: template argument may not be an abstract class");
using offset_policy = default_accessor;
using element_type = _ElementType;
using reference = _ElementType&;
using data_handle_type = _ElementType*;
_CCCL_HIDE_FROM_ABI constexpr default_accessor() noexcept = default;
_CCCL_TEMPLATE(class _OtherElementType)
_CCCL_REQUIRES(is_convertible_v<_OtherElementType (*)[], element_type (*)[]>)
_CCCL_API constexpr default_accessor(default_accessor<_OtherElementType>) noexcept {}
[[nodiscard]] _CCCL_API constexpr reference access(data_handle_type __p, size_t __i) const noexcept
{
return __p[__i];
}
[[nodiscard]] _CCCL_API constexpr data_handle_type offset(data_handle_type __p, size_t __i) const noexcept
{
return __p + __i;
}
};
_CCCL_END_NAMESPACE_CUDA_STD
#include <cuda/std/__cccl/epilogue.h>
#endif // _CUDA_STD___MDSPAN_DEFAULT_ACCESSOR_H

View File

@@ -0,0 +1,368 @@
//===----------------------------------------------------------------------===//
//
// Part of libcu++, the C++ Standard Library for your entire system,
// 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
// SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES.
//
//===----------------------------------------------------------------------===//
#ifndef _CUDA_STD___MDSPAN_EMPTY_BASE_H
#define _CUDA_STD___MDSPAN_EMPTY_BASE_H
#include <cuda/std/detail/__config>
#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 <cuda/std/__type_traits/enable_if.h>
#include <cuda/std/__type_traits/is_constructible.h>
#include <cuda/std/__type_traits/is_default_constructible.h>
#include <cuda/std/__type_traits/is_empty.h>
#include <cuda/std/__type_traits/is_nothrow_constructible.h>
#include <cuda/std/__type_traits/is_nothrow_default_constructible.h>
#include <cuda/std/__type_traits/is_swappable.h>
#include <cuda/std/__type_traits/remove_cvref.h>
#include <cuda/std/__utility/forward.h>
#include <cuda/std/__cccl/prologue.h>
_CCCL_BEGIN_NAMESPACE_CUDA_STD
template <size_t _Index, class _Elem, bool = is_empty_v<_Elem>>
struct _CCCL_DECLSPEC_EMPTY_BASES __mdspan_ebco_impl
{
_Elem __elem_;
_CCCL_EXEC_CHECK_DISABLE
_CCCL_TEMPLATE(class _Elem_ = _Elem)
_CCCL_REQUIRES(is_default_constructible_v<_Elem_>)
_CCCL_API constexpr __mdspan_ebco_impl() noexcept(is_nothrow_default_constructible_v<_Elem_>)
: __elem_()
{}
_CCCL_EXEC_CHECK_DISABLE
_CCCL_TEMPLATE(class... _Args)
_CCCL_REQUIRES((sizeof...(_Args) != 0) _CCCL_AND is_constructible_v<_Elem, _Args...>)
_CCCL_API constexpr __mdspan_ebco_impl(_Args&&... __args) noexcept(is_nothrow_constructible_v<_Elem, _Args...>)
: __elem_(::cuda::std::forward<_Args>(__args)...)
{}
[[nodiscard]] _CCCL_API constexpr _Elem& __get() noexcept
{
return __elem_;
}
[[nodiscard]] _CCCL_API constexpr const _Elem& __get() const noexcept
{
return __elem_;
}
};
template <size_t _Index, class _Elem>
struct _CCCL_DECLSPEC_EMPTY_BASES __mdspan_ebco_impl<_Index, _Elem, true> : _Elem
{
_CCCL_EXEC_CHECK_DISABLE
_CCCL_TEMPLATE(class _Elem_ = _Elem)
_CCCL_REQUIRES(is_default_constructible_v<_Elem_>)
_CCCL_API constexpr __mdspan_ebco_impl() noexcept(is_nothrow_default_constructible_v<_Elem_>)
: _Elem()
{}
_CCCL_EXEC_CHECK_DISABLE
_CCCL_TEMPLATE(class... _Args)
_CCCL_REQUIRES((sizeof...(_Args) != 0) _CCCL_AND is_constructible_v<_Elem, _Args...>)
_CCCL_API constexpr __mdspan_ebco_impl(_Args&&... __args) noexcept(is_nothrow_constructible_v<_Elem, _Args...>)
: _Elem(::cuda::std::forward<_Args>(__args)...)
{}
[[nodiscard]] _CCCL_API constexpr _Elem& __get() noexcept
{
return *static_cast<_Elem*>(this);
}
[[nodiscard]] _CCCL_API constexpr const _Elem& __get() const noexcept
{
return *static_cast<const _Elem*>(this);
}
};
template <class...>
struct _CCCL_DECLSPEC_EMPTY_BASES __mdspan_ebco;
template <class _Elem1>
struct _CCCL_DECLSPEC_EMPTY_BASES __mdspan_ebco<_Elem1> : __mdspan_ebco_impl<0, _Elem1>
{
using __base1 = __mdspan_ebco_impl<0, _Elem1>;
_CCCL_EXEC_CHECK_DISABLE
_CCCL_TEMPLATE(class _Elem1_ = _Elem1)
_CCCL_REQUIRES(is_default_constructible_v<_Elem1_>)
_CCCL_API constexpr __mdspan_ebco() noexcept(is_nothrow_default_constructible_v<_Elem1_>)
: __base1()
{}
_CCCL_EXEC_CHECK_DISABLE
_CCCL_TEMPLATE(class... _Args)
_CCCL_REQUIRES((sizeof...(_Args) != 0) _CCCL_AND is_constructible_v<_Elem1, _Args...>)
_CCCL_API constexpr __mdspan_ebco(_Args&&... __args) noexcept(is_nothrow_constructible_v<_Elem1, _Args...>)
: __base1(::cuda::std::forward<_Args>(__args)...)
{}
_CCCL_TEMPLATE(size_t _Index)
_CCCL_REQUIRES((_Index < 1))
[[nodiscard]] _CCCL_API constexpr _Elem1& __get() noexcept
{
return static_cast<__base1*>(this)->__get();
}
_CCCL_TEMPLATE(size_t _Index)
_CCCL_REQUIRES((_Index < 1))
[[nodiscard]] _CCCL_API constexpr const _Elem1& __get() const noexcept
{
return static_cast<const __base1*>(this)->__get();
}
_CCCL_EXEC_CHECK_DISABLE
_CCCL_API friend constexpr void swap(__mdspan_ebco& __x, __mdspan_ebco& __y) noexcept(is_nothrow_swappable_v<_Elem1>)
{
swap(__x.__get<0>(), __y.__get<0>());
}
};
template <class _Elem1, class _Elem2>
struct _CCCL_DECLSPEC_EMPTY_BASES __mdspan_ebco<_Elem1, _Elem2>
: __mdspan_ebco_impl<0, _Elem1>
, __mdspan_ebco_impl<1, _Elem2>
{
using __base1 = __mdspan_ebco_impl<0, _Elem1>;
using __base2 = __mdspan_ebco_impl<1, _Elem2>;
_CCCL_EXEC_CHECK_DISABLE
_CCCL_TEMPLATE(class _Elem1_ = _Elem1, class _Elem2_ = _Elem2)
_CCCL_REQUIRES(is_default_constructible_v<_Elem1_> _CCCL_AND is_default_constructible_v<_Elem2_>)
_CCCL_API constexpr __mdspan_ebco() noexcept(is_nothrow_default_constructible_v<_Elem1_>
&& is_nothrow_default_constructible_v<_Elem2_>)
: __base1()
, __base2()
{}
_CCCL_HIDE_FROM_ABI constexpr __mdspan_ebco(const __mdspan_ebco&) = default;
_CCCL_HIDE_FROM_ABI constexpr __mdspan_ebco(__mdspan_ebco&&) = default;
_CCCL_HIDE_FROM_ABI constexpr __mdspan_ebco& operator=(const __mdspan_ebco&) = default;
_CCCL_HIDE_FROM_ABI constexpr __mdspan_ebco& operator=(__mdspan_ebco&&) = default;
template <class _Arg1>
static constexpr bool __is_constructible_from_one_arg =
is_constructible_v<_Elem1, _Arg1> && is_default_constructible_v<_Elem2>;
template <class _Arg1>
static constexpr bool __is_nothrow_constructible_from_one_arg =
is_nothrow_constructible_v<_Elem1, _Arg1> && is_nothrow_default_constructible_v<_Elem2>;
// The converting constructor's constraint __is_constructible_from_one_arg<const __mdspan_ebco&> creates a circular
// dependency in C++20 concepts evaluation on Clang
// NOLINTBEGIN(bugprone-forwarding-reference-overload)
_CCCL_EXEC_CHECK_DISABLE
_CCCL_TEMPLATE(class _Arg1)
_CCCL_REQUIRES((!is_same_v<__mdspan_ebco, remove_cvref_t<_Arg1>>) _CCCL_AND __is_constructible_from_one_arg<_Arg1>)
_CCCL_API constexpr __mdspan_ebco(_Arg1&& __arg1) noexcept(__is_nothrow_constructible_from_one_arg<_Arg1>)
: __base1(::cuda::std::forward<_Arg1>(__arg1))
, __base2()
{}
// NOLINTEND(bugprone-forwarding-reference-overload)
template <class _Arg1, class _Arg2>
static constexpr bool __is_constructible_from_two_args =
is_constructible_v<_Elem1, _Arg1> && is_constructible_v<_Elem2, _Arg2>;
template <class _Arg1, class _Arg2>
static constexpr bool __is_nothrow_constructible_from_two_args =
is_nothrow_constructible_v<_Elem1, _Arg1> && is_nothrow_constructible_v<_Elem2, _Arg2>;
_CCCL_EXEC_CHECK_DISABLE
_CCCL_TEMPLATE(class _Arg1, class _Arg2)
_CCCL_REQUIRES(__is_constructible_from_two_args<_Arg1, _Arg2>)
_CCCL_API constexpr __mdspan_ebco(_Arg1&& __arg1,
_Arg2&& __arg2) noexcept(__is_nothrow_constructible_from_two_args<_Arg1, _Arg2>)
: __base1(::cuda::std::forward<_Arg1>(__arg1))
, __base2(::cuda::std::forward<_Arg2>(__arg2))
{}
_CCCL_TEMPLATE(size_t _Index)
_CCCL_REQUIRES((_Index < 2))
[[nodiscard]] _CCCL_API constexpr decltype(auto) __get() noexcept
{
if constexpr (_Index == 0)
{
return static_cast<__base1*>(this)->__get();
}
else // if constexpr (_Index == 1)
{
return static_cast<__base2*>(this)->__get();
}
}
_CCCL_TEMPLATE(size_t _Index)
_CCCL_REQUIRES((_Index < 2))
[[nodiscard]] _CCCL_API constexpr decltype(auto) __get() const noexcept
{
if constexpr (_Index == 0)
{
return static_cast<const __base1*>(this)->__get();
}
else // if constexpr (_Index == 1)
{
return static_cast<const __base2*>(this)->__get();
}
}
_CCCL_EXEC_CHECK_DISABLE
_CCCL_API friend constexpr void swap(__mdspan_ebco& __x, __mdspan_ebco& __y) noexcept(
is_nothrow_swappable_v<_Elem1> && is_nothrow_swappable_v<_Elem2>)
{
swap(__x.__get<0>(), __y.__get<0>());
swap(__x.__get<1>(), __y.__get<1>());
}
};
template <class _Elem1, class _Elem2, class _Elem3>
struct _CCCL_DECLSPEC_EMPTY_BASES __mdspan_ebco<_Elem1, _Elem2, _Elem3>
: __mdspan_ebco_impl<0, _Elem1>
, __mdspan_ebco_impl<1, _Elem2>
, __mdspan_ebco_impl<2, _Elem3>
{
using __base1 = __mdspan_ebco_impl<0, _Elem1>;
using __base2 = __mdspan_ebco_impl<1, _Elem2>;
using __base3 = __mdspan_ebco_impl<2, _Elem3>;
_CCCL_EXEC_CHECK_DISABLE
_CCCL_TEMPLATE(class _Elem1_ = _Elem1, class _Elem2_ = _Elem2, class _Elem3_ = _Elem3)
_CCCL_REQUIRES(is_default_constructible_v<_Elem1_> _CCCL_AND is_default_constructible_v<_Elem2_> _CCCL_AND
is_default_constructible_v<_Elem3_>)
_CCCL_API constexpr __mdspan_ebco() noexcept(
is_nothrow_default_constructible_v<_Elem1_> && is_nothrow_default_constructible_v<_Elem2_>
&& is_nothrow_default_constructible_v<_Elem3_>)
: __base1()
, __base2()
, __base3()
{}
_CCCL_HIDE_FROM_ABI constexpr __mdspan_ebco(const __mdspan_ebco&) = default;
_CCCL_HIDE_FROM_ABI constexpr __mdspan_ebco(__mdspan_ebco&&) = default;
_CCCL_HIDE_FROM_ABI constexpr __mdspan_ebco& operator=(const __mdspan_ebco&) = default;
_CCCL_HIDE_FROM_ABI constexpr __mdspan_ebco& operator=(__mdspan_ebco&&) = default;
template <class _Arg1>
static constexpr bool __is_constructible_from_one_arg =
is_constructible_v<_Elem1, _Arg1> && is_default_constructible_v<_Elem2> && is_default_constructible_v<_Elem3>;
template <class _Arg1>
static constexpr bool __is_nothrow_constructible_from_one_arg =
is_nothrow_constructible_v<_Elem1, _Arg1> && is_nothrow_default_constructible_v<_Elem2>
&& is_nothrow_default_constructible_v<_Elem3>;
// NOLINTBEGIN(bugprone-forwarding-reference-overload)
_CCCL_EXEC_CHECK_DISABLE
_CCCL_TEMPLATE(class _Arg1)
_CCCL_REQUIRES((!is_same_v<__mdspan_ebco, remove_cvref_t<_Arg1>>) _CCCL_AND __is_constructible_from_one_arg<_Arg1>)
_CCCL_API constexpr __mdspan_ebco(_Arg1&& __arg1) noexcept(__is_nothrow_constructible_from_one_arg<_Arg1>)
: __base1(::cuda::std::forward<_Arg1>(__arg1))
, __base2()
, __base3()
{}
// NOLINTEND(bugprone-forwarding-reference-overload)
template <class _Arg1, class _Arg2>
static constexpr bool __is_constructible_from_two_args =
is_constructible_v<_Elem1, _Arg1> && is_constructible_v<_Elem2, _Arg2> && is_default_constructible_v<_Elem3>;
template <class _Arg1, class _Arg2>
static constexpr bool __is_nothrow_constructible_from_two_args =
is_nothrow_constructible_v<_Elem1, _Arg1> && is_nothrow_constructible_v<_Elem2, _Arg2>
&& is_nothrow_default_constructible_v<_Elem3>;
_CCCL_EXEC_CHECK_DISABLE
_CCCL_TEMPLATE(class _Arg1, class _Arg2)
_CCCL_REQUIRES(__is_constructible_from_two_args<_Arg1, _Arg2>)
_CCCL_API constexpr __mdspan_ebco(_Arg1&& __arg1,
_Arg2&& __arg2) noexcept(__is_nothrow_constructible_from_two_args<_Arg1, _Arg2>)
: __base1(::cuda::std::forward<_Arg1>(__arg1))
, __base2(::cuda::std::forward<_Arg2>(__arg2))
, __base3()
{}
template <class _Arg1, class _Arg2, class _Arg3>
static constexpr bool __is_constructible_from_three_args =
is_constructible_v<_Elem1, _Arg1> && is_constructible_v<_Elem2, _Arg2> && is_constructible_v<_Elem3, _Arg3>;
template <class _Arg1, class _Arg2, class _Arg3>
static constexpr bool __is_nothrow_constructible_from_three_args =
is_nothrow_constructible_v<_Elem1, _Arg1> && is_nothrow_constructible_v<_Elem2, _Arg2>
&& is_nothrow_constructible_v<_Elem3, _Arg3>;
_CCCL_EXEC_CHECK_DISABLE
_CCCL_TEMPLATE(class _Arg1, class _Arg2, class _Arg3)
_CCCL_REQUIRES(__is_constructible_from_three_args<_Arg1, _Arg2, _Arg3>)
_CCCL_API constexpr __mdspan_ebco(_Arg1&& __arg1, _Arg2&& __arg2, _Arg3&& __arg3) noexcept(
__is_nothrow_constructible_from_three_args<_Arg1, _Arg2, _Arg3>)
: __base1(::cuda::std::forward<_Arg1>(__arg1))
, __base2(::cuda::std::forward<_Arg2>(__arg2))
, __base3(::cuda::std::forward<_Arg3>(__arg3))
{}
_CCCL_TEMPLATE(size_t _Index)
_CCCL_REQUIRES((_Index < 3))
[[nodiscard]] _CCCL_API constexpr decltype(auto) __get() noexcept
{
if constexpr (_Index == 0)
{
return static_cast<__base1*>(this)->__get();
}
else if constexpr (_Index == 1)
{
return static_cast<__base2*>(this)->__get();
}
else // if constexpr (_Index == 2)
{
return static_cast<__base3*>(this)->__get();
}
}
_CCCL_TEMPLATE(size_t _Index)
_CCCL_REQUIRES((_Index < 3))
[[nodiscard]] _CCCL_API constexpr decltype(auto) __get() const noexcept
{
if constexpr (_Index == 0)
{
return static_cast<const __base1*>(this)->__get();
}
else if constexpr (_Index == 1)
{
return static_cast<const __base2*>(this)->__get();
}
else // if constexpr (_Index == 2)
{
return static_cast<const __base3*>(this)->__get();
}
}
_CCCL_EXEC_CHECK_DISABLE
_CCCL_API friend constexpr void swap(__mdspan_ebco& __x, __mdspan_ebco& __y) noexcept(
is_nothrow_swappable_v<_Elem1> && is_nothrow_swappable_v<_Elem2> && is_nothrow_swappable_v<_Elem3>)
{
swap(__x.__get<0>(), __y.__get<0>());
swap(__x.__get<1>(), __y.__get<1>());
swap(__x.__get<2>(), __y.__get<2>());
}
};
_CCCL_END_NAMESPACE_CUDA_STD
#include <cuda/std/__cccl/epilogue.h>
#endif // _CUDA_STD___MDSPAN_EMPTY_BASE_H

View File

@@ -0,0 +1,727 @@
// -*- 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
// SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES.
//
// 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.
//
//===---------------------------------------------------------------------===//
#ifndef _CUDA_STD___MDSPAN_EXTENTS_H
#define _CUDA_STD___MDSPAN_EXTENTS_H
#include <cuda/std/detail/__config>
#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 <cuda/std/__concepts/concept_macros.h>
#include <cuda/std/__mdspan/concepts.h>
#include <cuda/std/__type_traits/common_type.h>
#include <cuda/std/__type_traits/fold.h>
#include <cuda/std/__type_traits/integral_constant.h>
#include <cuda/std/__type_traits/is_convertible.h>
#include <cuda/std/__type_traits/is_integer.h>
#include <cuda/std/__type_traits/is_nothrow_constructible.h>
#include <cuda/std/__type_traits/is_same.h>
#include <cuda/std/__type_traits/make_nbit_int.h>
#include <cuda/std/__type_traits/make_unsigned.h>
#include <cuda/std/__type_traits/num_bits.h>
#include <cuda/std/__utility/cmp.h>
#include <cuda/std/__utility/integer_sequence.h>
#include <cuda/std/__utility/unreachable.h>
#include <cuda/std/array>
#include <cuda/std/concepts>
#include <cuda/std/cstddef>
#include <cuda/std/limits>
#include <cuda/std/span>
#include <cuda/std/__cccl/prologue.h>
_CCCL_BEGIN_NAMESPACE_CUDA_STD
namespace __mdspan_detail
{
// ------------------------------------------------------------------
// ------------ __static_array --------------------------------------
// ------------------------------------------------------------------
// array like class which provides an array of static values with get
template <class _Tp, _Tp... _Values>
struct __static_array
{
[[nodiscard]] _CCCL_API static constexpr size_t __size() noexcept
{
return sizeof...(_Values);
}
[[nodiscard]] _CCCL_API static constexpr _Tp __get(size_t __index) noexcept
{
constexpr array<_Tp, sizeof...(_Values)> __array = {_Values...};
return __array[__index];
}
template <size_t _Index>
[[nodiscard]] _CCCL_API static constexpr _Tp __get()
{
return __get(_Index);
}
};
// ------------------------------------------------------------------
// ------------ __possibly_empty_array -----------------------------
// ------------------------------------------------------------------
// array like class which provides get function and operator [], and
// has a specialization for the size 0 case.
// This is needed to make the __maybe_static_array be truly empty, for
// all static values.
template <class _Tp, size_t _Size>
struct __possibly_empty_array
{
_Tp __vals_[_Size];
[[nodiscard]] _CCCL_API constexpr _Tp& operator[](size_t __index)
{
return __vals_[__index];
}
[[nodiscard]] _CCCL_API constexpr const _Tp& operator[](size_t __index) const
{
return __vals_[__index];
}
};
template <class _Tp>
struct __possibly_empty_array<_Tp, 0>
{
#if _CCCL_COMPILER(MSVC)
_CCCL_API constexpr _Tp& operator[](size_t __index)
{
return *__get(__index);
}
_CCCL_API constexpr const _Tp& operator[](size_t __index) const
{
return *__get(__index);
}
_CCCL_API constexpr _Tp* __get(size_t)
{
return nullptr;
}
_CCCL_API constexpr const _Tp* __get(size_t) const
{
return nullptr;
}
#else // ^^^ _CCCL_COMPILER(MSVC) ^^^ / vvv !_CCCL_COMPILER(MSVC) vvv
_CCCL_API constexpr _Tp& operator[](size_t)
{
_CCCL_UNREACHABLE();
}
_CCCL_API constexpr const _Tp& operator[](size_t) const
{
_CCCL_UNREACHABLE();
}
#endif // !_CCCL_COMPILER(MSVC)
};
// ------------------------------------------------------------------
// ------------ static_partial_sums ---------------------------------
// ------------------------------------------------------------------
// Provides a compile time partial sum one can index into
template <size_t... _Values>
struct __static_partial_sums
{
[[nodiscard]] _CCCL_API static constexpr array<size_t, sizeof...(_Values)> __static_partial_sums_impl()
{
array<size_t, sizeof...(_Values)> __values{_Values...};
array<size_t, sizeof...(_Values)> __partial_sums{{}};
size_t __running_sum = 0;
for (int __i = 0; __i != sizeof...(_Values); ++__i)
{
__partial_sums[__i] = __running_sum;
__running_sum += __values[__i];
}
return __partial_sums;
}
[[nodiscard]] _CCCL_API static constexpr size_t __get(size_t __index)
{
constexpr array<size_t, sizeof...(_Values)> __result = __static_partial_sums_impl();
return __result[__index];
}
};
// ------------------------------------------------------------------
// ------------ __maybe_static_array --------------------------------
// ------------------------------------------------------------------
template <class _TStatic, _TStatic _DynTag, _TStatic... _Values>
inline constexpr size_t __count_dynamic_v = (size_t{0} + ... + static_cast<size_t>(_Values == _DynTag));
_CCCL_DIAG_PUSH
_CCCL_DIAG_SUPPRESS_MSVC(4702) // Unreachable code
// array like class which has a mix of static and runtime values but
// only stores the runtime values.
// The type of the static and the runtime values can be different.
// The position of a dynamic value is indicated through a tag value.
// We manually implement EBCO because MSVC and some odler compiler fail hard with [[no_unique_address]]
template <class _TDynamic, class _TStatic, _TStatic _DynTag, _TStatic... _Values>
struct _CCCL_DECLSPEC_EMPTY_BASES
__maybe_static_array : private __possibly_empty_array<_TDynamic, __count_dynamic_v<_TStatic, _DynTag, _Values...>>
{
static_assert(is_convertible_v<_TStatic, _TDynamic>,
"__maybe_static_array: _TStatic must be convertible to _TDynamic");
static_assert(is_convertible_v<_TDynamic, _TStatic>,
"__maybe_static_array: _TDynamic must be convertible to _TStatic");
private:
// Static values member
static constexpr size_t __size_ = sizeof...(_Values);
static constexpr size_t __size_dynamic_ = __count_dynamic_v<_TStatic, _DynTag, _Values...>;
using _StaticValues = __static_array<_TStatic, _Values...>;
using _DynamicValues = __possibly_empty_array<_TDynamic, __size_dynamic_>;
// static mapping of indices to the position in the dynamic values array
using _DynamicIdxMap = __static_partial_sums<static_cast<size_t>(_Values == _DynTag)...>;
template <size_t... Indices>
[[nodiscard]] _CCCL_API static constexpr _DynamicValues __zeros(index_sequence<Indices...>) noexcept
{
return _DynamicValues{((void) Indices, 0)...};
}
public:
_CCCL_API constexpr __maybe_static_array() noexcept
: _DynamicValues{__zeros(make_index_sequence<__size_dynamic_>())}
{}
template <class _Tp, size_t _Size>
_CCCL_API constexpr __maybe_static_array(span<_Tp, _Size> __vals) noexcept
: _DynamicValues{}
{
if constexpr (_Size == __size_dynamic_)
{
for (size_t __i = 0; __i != _Size; __i++)
{
(*static_cast<_DynamicValues*>(this))[__i] = static_cast<_TDynamic>(__vals[__i]);
}
}
else
{
for (size_t __i = 0; __i != __size_; __i++)
{
_TStatic __static_val = _StaticValues::__get(__i);
if (__static_val == _DynTag)
{
(*static_cast<_DynamicValues*>(this))[_DynamicIdxMap::__get(__i)] = static_cast<_TDynamic>(__vals[__i]);
}
else
{
// Not catching this could lead to out of bounds errors later
// e.g. using my_mdspan_t = mdspan<int, extents<int, 10>>; my_mdspan_t = m(new int[N], span<int,1>(&N));
// Right-hand-side construction looks ok with allocation and size matching,
// but since (potentially elsewhere defined) my_mdspan_t has static size m now thinks its range is 10 not N
_CCCL_ASSERT(static_cast<_TDynamic>(__vals[__i]) == static_cast<_TDynamic>(__static_val),
"extents construction: mismatch of provided arguments with static extents.");
}
}
}
}
// constructors from dynamic values only -- this covers the case for rank() == 0
_CCCL_TEMPLATE(class... _DynVals)
_CCCL_REQUIRES((sizeof...(_DynVals) == __size_dynamic_) _CCCL_AND(!__fold_and_v<__is_cuda_std_span_v<_DynVals>...>))
_CCCL_API constexpr __maybe_static_array(_DynVals... __vals) noexcept
: _DynamicValues{static_cast<_TDynamic>(__vals)...}
{}
// constructors from all values -- here rank will be greater than 0
_CCCL_TEMPLATE(class... _DynVals)
_CCCL_REQUIRES((sizeof...(_DynVals) != __size_dynamic_) _CCCL_AND(!__fold_and_v<__is_cuda_std_span_v<_DynVals>...>))
_CCCL_API constexpr __maybe_static_array(_DynVals... __vals)
: _DynamicValues{}
{
static_assert((sizeof...(_DynVals) == __size_), "Invalid number of values.");
_TDynamic __values[__size_] = {static_cast<_TDynamic>(__vals)...};
for (size_t __i = 0; __i < __size_; __i++)
{
_TStatic __static_val = _StaticValues::__get(__i);
if (__static_val == _DynTag)
{
(*static_cast<_DynamicValues*>(this))[_DynamicIdxMap::__get(__i)] = __values[__i];
}
else
{
// Not catching this could lead to out of bounds errors later
// e.g. using my_mdspan_t = mdspan<int, extents<int, 10>>; my_mdspan_t = m(new int[5], 5);
// Right-hand-side construction looks ok with allocation and size matching,
// but since (potentially elsewhere defined) my_mdspan_t has static size m now thinks its range is 10 not 5
_CCCL_ASSERT(__values[__i] == static_cast<_TDynamic>(__static_val),
"extents construction: mismatch of provided arguments with static extents.");
}
}
}
// access functions
[[nodiscard]] _CCCL_API static constexpr _TStatic __static_value(size_t __i) noexcept
{
if constexpr (__size_ > 0)
{
_CCCL_ASSERT(__i < __size_, "extents access: index must be less than rank");
}
return _StaticValues::__get(__i);
}
[[nodiscard]] _CCCL_API constexpr _TDynamic __value(size_t __i) const
{
if constexpr (__size_ > 0)
{
_CCCL_ASSERT(__i < __size_, "extents access: index must be less than rank");
}
_TStatic __static_val = _StaticValues::__get(__i);
return __static_val == _DynTag
? (*static_cast<const _DynamicValues*>(this))[_DynamicIdxMap::__get(__i)]
: static_cast<_TDynamic>(__static_val);
}
[[nodiscard]] _CCCL_API constexpr _TDynamic operator[](size_t __i) const
{
if constexpr (__size_ > 0)
{
_CCCL_ASSERT(__i < __size_, "extents access: index must be less than rank");
}
return __value(__i);
}
// observers
[[nodiscard]] _CCCL_API static constexpr size_t __size()
{
return __size_;
}
[[nodiscard]] _CCCL_API static constexpr size_t __size_dynamic()
{
return __size_dynamic_;
}
};
_CCCL_DIAG_POP // MSVC(4702) Unreachable code
template <class _To, class _From>
inline constexpr bool __potentially_narrowing =
static_cast<make_unsigned_t<_To>>((numeric_limits<_To>::max)())
< static_cast<make_unsigned_t<_From>>((numeric_limits<_From>::max)());
// Function to check whether a value is representable as another type
// value must be a positive integer otherwise returns false
// if _From is not an integral, we just check positivity
_CCCL_TEMPLATE(class _To, class _From)
_CCCL_REQUIRES(__cccl_is_integer_v<_To>)
[[nodiscard]] _CCCL_API constexpr bool __is_representable_as([[maybe_unused]] _From __value)
{
if constexpr (integral<_From> && !is_same_v<_From, bool>)
{
using _FromInt = __make_nbit_int_t<__num_bits_v<_From>, is_signed_v<_From>>;
return ::cuda::std::in_range<_To>(static_cast<_FromInt>(__value));
}
else // !integral<_From>
{
if constexpr (is_signed_v<_To>)
{
return static_cast<_To>(__value) >= 0;
}
else // !is_signed_v<_To>
{
return true;
}
}
}
_CCCL_TEMPLATE(class _To, class... _From)
_CCCL_REQUIRES(__cccl_is_integer_v<_To>)
[[nodiscard]] _CCCL_API constexpr bool __are_representable_as(_From... __values)
{
return (__mdspan_detail::__is_representable_as<_To>(__values) && ... && true);
}
_CCCL_TEMPLATE(class _To, class _From, size_t _Size)
_CCCL_REQUIRES(__cccl_is_integer_v<_To>)
[[nodiscard]] _CCCL_API constexpr bool __are_representable_as(span<_From, _Size> __values)
{
bool __result = true;
for (size_t __i = 0; __i != _Size; __i++)
{
if (!__mdspan_detail::__is_representable_as<_To>(__values[__i]))
{
__result = false;
break;
}
}
return __result;
}
// ------------------------------------------------------------------
// ------------ __mul_overflow --------------------------------------
// ------------------------------------------------------------------
// Multiplies two values and detects overflow. Returns true if overflow occurred.
template <class _Tp>
[[nodiscard]] _CCCL_API constexpr bool __mul_overflow(_Tp __x, _Tp __y, _Tp* __res) noexcept
{
*__res = __x * __y;
return __x && ((*__res / __x) != __y);
}
template <class _Tp>
[[nodiscard]] _CCCL_API constexpr bool __mul_overflow(_Tp __x, _Tp __y) noexcept
{
const auto __res = __x * __y;
return __x && ((__res / __x) != __y);
}
} // namespace __mdspan_detail
// ------------------------------------------------------------------
// ------------ extents ---------------------------------------------
// ------------------------------------------------------------------
// Class to delegate between the different (non-)explicit constructors
struct __extent_delegate_tag
{};
// Class to describe the extents of a multi dimensional array.
// Used by mdspan, mdarray and layout mappings.
// See ISO C++ standard [mdspan.extents]
template <class _IndexType, size_t... _Extents>
class extents : private __mdspan_detail::__maybe_static_array<_IndexType, size_t, dynamic_extent, _Extents...>
{
public:
// typedefs for integral types used
using index_type = _IndexType;
using size_type = make_unsigned_t<index_type>;
using rank_type = size_t;
static_assert(__cccl_is_integer_v<index_type>, "extents::index_type must be a signed or unsigned integer type");
static_assert(((::cuda::std::in_range<index_type>(_Extents) || (_Extents == dynamic_extent)) && ...),
"extents ctor: arguments must be representable as index_type and nonnegative");
private:
static constexpr rank_type __rank_ = sizeof...(_Extents);
static constexpr rank_type __rank_dynamic_ =
(rank_type(0) + ... + (static_cast<rank_type>(_Extents == dynamic_extent)));
// internal storage type using __maybe_static_array
using _Values = __mdspan_detail::__maybe_static_array<_IndexType, size_t, dynamic_extent, _Extents...>;
public:
// [mdspan.extents.obs], observers of multidimensional index space
[[nodiscard]] _CCCL_API static constexpr rank_type rank() noexcept
{
return __rank_;
}
[[nodiscard]] _CCCL_API static constexpr rank_type rank_dynamic() noexcept
{
return __rank_dynamic_;
}
[[nodiscard]] _CCCL_API constexpr index_type extent(rank_type __r) const noexcept
{
return this->__value(__r);
}
[[nodiscard]] _CCCL_API static constexpr size_t static_extent(rank_type __r) noexcept
{
return _Values::__static_value(__r);
}
// [mdspan.extents.cons], constructors
_CCCL_HIDE_FROM_ABI constexpr extents() noexcept = default;
// Construction from just dynamic or all values.
// Precondition check is deferred to __maybe_static_array constructor
_CCCL_TEMPLATE(class... _OtherIndexTypes)
_CCCL_REQUIRES((sizeof...(_OtherIndexTypes) == __rank_ || sizeof...(_OtherIndexTypes) == __rank_dynamic_)
_CCCL_AND __mdspan_detail::__all_convertible_to_index_type<index_type, _OtherIndexTypes...>)
_CCCL_API constexpr explicit extents(_OtherIndexTypes... __dynvals) noexcept
: _Values(static_cast<index_type>(__dynvals)...)
{
// Not catching this could lead to out of bounds errors later
// e.g. mdspan m(ptr, dextents<char, 1>(200u)); leads to an extent of -56 on m
_CCCL_ASSERT(__mdspan_detail::__are_representable_as<index_type>(__dynvals...),
"extents ctor: arguments must be representable as index_type and nonnegative");
}
template <class _OtherIndexType>
static constexpr bool __is_convertible_to_index_type =
is_convertible_v<const _OtherIndexType&, index_type>
&& is_nothrow_constructible_v<index_type, const _OtherIndexType&>;
_CCCL_TEMPLATE(class _OtherIndexType, size_t _Size)
_CCCL_REQUIRES((_Size == __rank_dynamic_) _CCCL_AND __is_convertible_to_index_type<_OtherIndexType>)
_CCCL_API constexpr extents(const array<_OtherIndexType, _Size>& __exts) noexcept
: extents(span<const _OtherIndexType, _Size>(__exts))
{}
_CCCL_TEMPLATE(class _OtherIndexType, size_t _Size)
_CCCL_REQUIRES((_Size == __rank_) _CCCL_AND(_Size != __rank_dynamic_)
_CCCL_AND __is_convertible_to_index_type<_OtherIndexType>)
_CCCL_API explicit constexpr extents(const array<_OtherIndexType, _Size>& __exts) noexcept
: extents(span<const _OtherIndexType, _Size>(__exts))
{}
_CCCL_TEMPLATE(class _OtherIndexType, size_t _Size)
_CCCL_REQUIRES((_Size == __rank_dynamic_) _CCCL_AND __is_convertible_to_index_type<_OtherIndexType>)
_CCCL_API constexpr extents(span<_OtherIndexType, _Size> __exts) noexcept
: _Values(__exts)
{
// Not catching this could lead to out of bounds errors later
// e.g. array a{200u}; mdspan<int, dextents<char,1>> m(ptr, extents(span<unsigned,1>(a))); leads to an extent of -56
// on m
_CCCL_ASSERT(__mdspan_detail::__are_representable_as<index_type>(__exts),
"extents ctor: arguments must be representable as index_type and nonnegative");
}
_CCCL_TEMPLATE(class _OtherIndexType, size_t _Size)
_CCCL_REQUIRES((_Size != __rank_dynamic_) _CCCL_AND(_Size == __rank_)
_CCCL_AND __is_convertible_to_index_type<_OtherIndexType>)
_CCCL_API explicit constexpr extents(span<_OtherIndexType, _Size> __exts) noexcept
: _Values(__exts)
{
// Not catching this could lead to out of bounds errors later
// e.g. array a{200u}; mdspan<int, dextents<char,1>> m(ptr, extents(span<unsigned,1>(a))); leads to an extent of -56
// on m
_CCCL_ASSERT(__mdspan_detail::__are_representable_as<index_type>(__exts),
"extents ctor: arguments must be representable as index_type and nonnegative");
}
private:
// Function to construct extents storage from other extents.
template <size_t _DynCount, size_t _Idx, class _OtherExtents, class... _DynamicValues>
[[nodiscard]] _CCCL_API constexpr _Values __construct_vals_from_extents(
integral_constant<size_t, _DynCount>,
integral_constant<size_t, _Idx>,
[[maybe_unused]] const _OtherExtents& __exts,
_DynamicValues... __dynamic_values) noexcept
{
if constexpr (_Idx == __rank_)
{
if constexpr (_DynCount == __rank_dynamic_)
{
return _Values{static_cast<index_type>(__dynamic_values)...};
}
else
{
static_assert(_DynCount == __rank_dynamic_, "Constructor of invalid extents passed to extent::extent");
_CCCL_UNREACHABLE();
}
}
else // _Idx < __rank_
{
if constexpr (static_extent(_Idx) == dynamic_extent)
{
return __construct_vals_from_extents(
integral_constant<size_t, _DynCount + 1>(),
integral_constant<size_t, _Idx + 1>(),
__exts,
__dynamic_values...,
__exts.extent(_Idx));
}
else // static_extent(_Idx) != dynamic_extent
{
return __construct_vals_from_extents(
integral_constant<size_t, _DynCount>(), integral_constant<size_t, _Idx + 1>(), __exts, __dynamic_values...);
}
}
}
template <class _OtherIndexType, size_t... _OtherExtents>
_CCCL_API constexpr extents(__extent_delegate_tag, const extents<_OtherIndexType, _OtherExtents...>& __other) noexcept
: _Values(__construct_vals_from_extents(integral_constant<size_t, 0>(), integral_constant<size_t, 0>(), __other))
{
if constexpr (rank() != 0)
{
for (size_t __r = 0; __r != rank(); __r++)
{
_CCCL_ASSERT(::cuda::std::in_range<index_type>(__other.extent(__r)),
"extents ctor: arguments must be representable as index_type and nonnegative");
// Not catching this could lead to out of bounds errors later
// e.g. mdspan<int, extents<int, 10>> m = mdspan<int, dextents<int, 1>>(new int[5], 5);
// Right-hand-side construction was ok, but m now thinks its range is 10 not 5
_CCCL_ASSERT(
(_Values::__static_value(__r) == dynamic_extent)
|| (static_cast<index_type>(__other.extent(__r)) == static_cast<index_type>(_Values::__static_value(__r))),
"extents construction: mismatch of provided arguments with static extents.");
}
}
}
public:
// Converting constructor from other extents specializations
template <class _OtherIndexType, size_t... _OtherExtents>
static constexpr bool __is_explicit_conversion =
(((_Extents != dynamic_extent) && (_OtherExtents == dynamic_extent)) || ...)
|| __mdspan_detail::__potentially_narrowing<index_type, _OtherIndexType>;
template <size_t... _OtherExtents>
static constexpr bool __is_matching_extents =
((_OtherExtents == dynamic_extent || _Extents == dynamic_extent || _OtherExtents == _Extents) && ... && true);
_CCCL_TEMPLATE(class _OtherIndexType, size_t... _OtherExtents)
_CCCL_REQUIRES((sizeof...(_OtherExtents) == sizeof...(_Extents)) _CCCL_AND __is_matching_extents<_OtherExtents...>
_CCCL_AND(!__is_explicit_conversion<_OtherIndexType, _OtherExtents...>))
_CCCL_API constexpr extents(const extents<_OtherIndexType, _OtherExtents...>& __other) noexcept
: extents(__extent_delegate_tag{}, __other)
{}
_CCCL_TEMPLATE(class _OtherIndexType, size_t... _OtherExtents)
_CCCL_REQUIRES((sizeof...(_OtherExtents) == sizeof...(_Extents))
_CCCL_AND __is_matching_extents<_OtherExtents...> _CCCL_AND
__is_explicit_conversion<_OtherIndexType, _OtherExtents...>)
_CCCL_API explicit constexpr extents(const extents<_OtherIndexType, _OtherExtents...>& __other) noexcept
: extents(__extent_delegate_tag{}, __other)
{}
// Comparison operator
template <class _OtherIndexType, size_t... _OtherExtents>
[[nodiscard]] _CCCL_API friend constexpr bool
operator==(const extents& __lhs, const extents<_OtherIndexType, _OtherExtents...>& __rhs) noexcept
{
if constexpr (rank() != sizeof...(_OtherExtents))
{
return false;
}
else if constexpr (rank() != 0)
{
bool __result = true;
for (rank_type __r = 0; __r != __rank_; __r++)
{
if (::cuda::std::cmp_not_equal(__lhs.extent(__r), __rhs.extent(__r)))
{
__result = false;
break;
}
}
return __result;
}
else // MSVC needs this or it complains about unreachable code in the first condition
{
return true;
}
}
#if _CCCL_STD_VER <= 2017
template <class _OtherIndexType, size_t... _OtherExtents>
[[nodiscard]] _CCCL_API friend constexpr bool
operator!=(const extents& __lhs, const extents<_OtherIndexType, _OtherExtents...>& __rhs) noexcept
{
return !(__lhs == __rhs);
}
#endif // _CCCL_STD_VER <= 2017
};
// nvcc cannot handle type conversions without this workaround
struct __to_dynamic_extent
{
template <class>
static constexpr size_t value = dynamic_extent;
};
// Deduction guide for extents
template <class... _IndexTypes>
_CCCL_DEDUCTION_GUIDE_ATTRIBUTES extents(_IndexTypes...)
-> extents<size_t, __to_dynamic_extent::template value<_IndexTypes>...>;
namespace __mdspan_detail
{
// ------------------------------------------------------------------
// ------------ __required_span_size_is_representable ---------------
// ------------------------------------------------------------------
// Checks if the product of extents is representable as index_type without overflow
template <class _Extents>
[[nodiscard]] _CCCL_API constexpr bool __required_span_size_is_representable(const _Extents& __ext) noexcept
{
using ::cuda::std::__mdspan_detail::__mul_overflow;
bool __result = true;
if constexpr (_Extents::rank() != 0)
{
using __index_type = typename _Extents::index_type;
using __rank_type = typename _Extents::rank_type;
__index_type __prod = __ext.extent(0);
for (__rank_type __r = 1; __r < _Extents::rank(); __r++)
{
if (__mul_overflow(__prod, __ext.extent(__r), &__prod))
{
__result = false;
break;
}
}
}
return __result;
}
// Function to check whether a set of indices are a multidimensional
// index into extents. This is a word of power in the C++ standard
// requiring that the indices are larger than 0 and smaller than
// the respective extents.
_CCCL_TEMPLATE(class _IndexType, class _From)
_CCCL_REQUIRES(integral<_IndexType>)
[[nodiscard]] _CCCL_API constexpr bool __is_index_in_extent(_IndexType __extent, _From __value)
{
if constexpr (integral<_From> && !is_same_v<_From, bool>)
{
using _FromInt = __make_nbit_int_t<__num_bits_v<_From>, is_signed_v<_From>>;
const auto __from_int = static_cast<_FromInt>(__value);
return ::cuda::std::cmp_greater_equal(__from_int, 0) && ::cuda::std::cmp_less(__from_int, __extent);
}
else
{
if constexpr (is_signed_v<_From>)
{
if (static_cast<_IndexType>(__value) < 0)
{
return false;
}
return static_cast<_IndexType>(__value) < __extent;
}
else
{
return static_cast<_IndexType>(__value) < __extent;
}
}
}
template <size_t... _Idxs, class _Extents, class... _From>
[[nodiscard]] _CCCL_API constexpr bool
__is_multidimensional_index_in_impl(index_sequence<_Idxs...>, const _Extents& __ext, _From... __values)
{
return (__mdspan_detail::__is_index_in_extent(__ext.extent(_Idxs), __values) && ...);
}
template <class _Extents, class... _From>
[[nodiscard]] _CCCL_API constexpr bool __is_multidimensional_index_in(const _Extents& __ext, _From... __values)
{
return __mdspan_detail::__is_multidimensional_index_in_impl(
make_index_sequence<_Extents::rank()>(), __ext, __values...);
}
} // namespace __mdspan_detail
_CCCL_END_NAMESPACE_CUDA_STD
#include <cuda/std/__cccl/epilogue.h>
#endif // _CUDA_STD___MDSPAN_EXTENTS_H

View File

@@ -0,0 +1,295 @@
// -*- 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
// SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES.
//
// 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.
//
//===---------------------------------------------------------------------===//
#ifndef _CUDA_STD___MDSPAN_LAYOUT_LEFT_H
#define _CUDA_STD___MDSPAN_LAYOUT_LEFT_H
#include <cuda/std/detail/__config>
#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 <cuda/std/__concepts/concept_macros.h>
#include <cuda/std/__fwd/mdspan.h>
#include <cuda/std/__mdspan/concepts.h>
#include <cuda/std/__mdspan/empty_base.h>
#include <cuda/std/__mdspan/extents.h>
#include <cuda/std/__type_traits/is_constructible.h>
#include <cuda/std/__type_traits/is_convertible.h>
#include <cuda/std/__type_traits/is_nothrow_constructible.h>
#include <cuda/std/__utility/integer_sequence.h>
#include <cuda/std/array>
#include <cuda/std/cstddef>
#include <cuda/std/limits>
#include <cuda/std/__cccl/prologue.h>
_CCCL_BEGIN_NAMESPACE_CUDA_STD
// Helper for lightweight test checking that one did pass a layout policy as LayoutPolicy template argument
template <class _Extents>
class _CCCL_DECLSPEC_EMPTY_BASES layout_left::mapping : private __mdspan_ebco<_Extents>
{
public:
static_assert(__is_cuda_std_extents_v<_Extents>,
"layout_left::mapping template argument must be a specialization of extents.");
using extents_type = _Extents;
using index_type = typename extents_type::index_type;
using size_type = typename extents_type::size_type;
using rank_type = typename extents_type::rank_type;
using layout_type = layout_left;
using __base = __mdspan_ebco<_Extents>;
template <class, class, class, class>
friend class mdspan;
private:
static_assert((extents_type::rank_dynamic() > 0)
|| ::cuda::std::__mdspan_detail::__required_span_size_is_representable(extents_type()),
"layout_left::mapping product of static extents must be representable as index_type.");
public:
// [mdspan.layout.left.cons], constructors
_CCCL_HIDE_FROM_ABI constexpr mapping() noexcept = default;
_CCCL_HIDE_FROM_ABI constexpr mapping(const mapping&) noexcept = default;
_CCCL_API constexpr mapping(const extents_type& __ext) noexcept
: __base(__ext)
{
// not catching this could lead to out-of-bounds access later when used inside mdspan
// mapping<dextents<char, 2>> map(dextents<char, 2>(40,40)); map(10, 3) == -126
_CCCL_ASSERT(::cuda::std::__mdspan_detail::__required_span_size_is_representable(__ext),
"layout_left::mapping extents ctor: product of extents must be representable as index_type.");
}
_CCCL_TEMPLATE(class _OtherExtents)
_CCCL_REQUIRES(is_constructible_v<extents_type, _OtherExtents> _CCCL_AND is_convertible_v<_OtherExtents, extents_type>)
_CCCL_API constexpr mapping(const mapping<_OtherExtents>& __other) noexcept
: __base(__other.extents())
{
// not catching this could lead to out-of-bounds access later when used inside mdspan
// mapping<dextents<char, 2>> map(mapping<dextents<int, 2>>(dextents<int, 2>(40,40))); map(10, 3) == -126
_CCCL_ASSERT(::cuda::std::__mdspan_detail::__is_representable_as<index_type>(__other.required_span_size()),
"layout_left::mapping converting ctor: other.required_span_size() must be representable as "
"index_type.");
}
_CCCL_TEMPLATE(class _OtherExtents)
_CCCL_REQUIRES(
is_constructible_v<extents_type, _OtherExtents> _CCCL_AND(!is_convertible_v<_OtherExtents, extents_type>))
_CCCL_API explicit constexpr mapping(const mapping<_OtherExtents>& __other) noexcept
: __base(__other.extents())
{
// not catching this could lead to out-of-bounds access later when used inside mdspan
// mapping<dextents<char, 2>> map(mapping<dextents<int, 2>>(dextents<int, 2>(40,40))); map(10, 3) == -126
_CCCL_ASSERT(::cuda::std::__mdspan_detail::__is_representable_as<index_type>(__other.required_span_size()),
"layout_left::mapping converting ctor: other.required_span_size() must be representable as "
"index_type.");
}
_CCCL_TEMPLATE(class _OtherExtents)
_CCCL_REQUIRES((_OtherExtents::rank() <= 1) _CCCL_AND is_constructible_v<extents_type, _OtherExtents> _CCCL_AND
is_convertible_v<_OtherExtents, extents_type>)
_CCCL_API constexpr mapping(const layout_right::mapping<_OtherExtents>& __other) noexcept
: __base(__other.extents())
{
// not catching this could lead to out-of-bounds access later when used inside mdspan
// Note: since this is constraint to rank 1, extents itself would catch the invalid conversion first
// and thus this assertion should never be triggered, but keeping it here for consistency
// layout_left::mapping<dextents<char, 1>> map(
// layout_right::mapping<dextents<unsigned, 1>>(dextents<unsigned, 1>(200))); map.extents().extent(0) ==
// -56
_CCCL_ASSERT(::cuda::std::__mdspan_detail::__is_representable_as<index_type>(__other.required_span_size()),
"layout_left::mapping converting ctor: other.required_span_size() must be representable as "
"index_type.");
}
_CCCL_TEMPLATE(class _OtherExtents)
_CCCL_REQUIRES((_OtherExtents::rank() <= 1) _CCCL_AND is_constructible_v<extents_type, _OtherExtents> _CCCL_AND(
!is_convertible_v<_OtherExtents, extents_type>))
_CCCL_API explicit constexpr mapping(const layout_right::mapping<_OtherExtents>& __other) noexcept
: __base(__other.extents())
{
// not catching this could lead to out-of-bounds access later when used inside mdspan
// Note: since this is constraint to rank 1, extents itself would catch the invalid conversion first
// and thus this assertion should never be triggered, but keeping it here for consistency
// layout_left::mapping<dextents<char, 1>> map(
// layout_right::mapping<dextents<unsigned, 1>>(dextents<unsigned, 1>(200))); map.extents().extent(0) ==
// -56
_CCCL_ASSERT(__mdspan_detail::__is_representable_as<index_type>(__other.required_span_size()),
"layout_left::mapping converting ctor: other.required_span_size() must be representable as "
"index_type.");
}
template <class _OtherMappping>
[[nodiscard]] _CCCL_API constexpr bool __check_strides(const _OtherMappping& __other) const noexcept
{
// avoid warning when comparing signed and unsigner integers and pick the wider of two types
using _CommonType = common_type_t<index_type, typename _OtherMappping::index_type>;
bool __result = true;
for (rank_type __r = 0; __r != extents_type::rank(); __r++)
{
if (static_cast<_CommonType>(stride(__r)) != static_cast<_CommonType>(__other.stride(__r)))
{
__result = false;
break;
}
}
return __result;
}
_CCCL_TEMPLATE(class _OtherExtents)
_CCCL_REQUIRES(is_constructible_v<extents_type, _OtherExtents> _CCCL_AND(extents_type::rank() > 0))
_CCCL_API explicit constexpr mapping(const layout_stride::mapping<_OtherExtents>& __other) noexcept
: __base(__other.extents())
{
_CCCL_ASSERT(__check_strides(__other),
"layout_left::mapping from layout_stride ctor: strides are not compatible with layout_left.");
_CCCL_ASSERT(::cuda::std::__mdspan_detail::__is_representable_as<index_type>(__other.required_span_size()),
"layout_left::mapping from layout_stride ctor: other.required_span_size() must be representable as "
"index_type.");
}
_CCCL_TEMPLATE(class _OtherExtents)
_CCCL_REQUIRES(is_constructible_v<extents_type, _OtherExtents> _CCCL_AND(extents_type::rank() == 0))
_CCCL_API constexpr mapping(const layout_stride::mapping<_OtherExtents>& __other) noexcept
: __base(__other.extents())
{}
_CCCL_HIDE_FROM_ABI constexpr mapping& operator=(const mapping&) noexcept = default;
// [mdspan.layout.left.obs], observers
[[nodiscard]] _CCCL_API constexpr const extents_type& extents() const noexcept
{
return this->template __get<0>();
}
[[nodiscard]] _CCCL_API constexpr index_type required_span_size() const noexcept
{
index_type __size = 1;
if constexpr (extents_type::rank() != 0)
{
for (size_t __r = 0; __r != extents_type::rank(); __r++)
{
__size *= extents().extent(__r);
}
}
return __size;
}
template <size_t... _Pos>
[[nodiscard]] _CCCL_API constexpr index_type
__op_index(const array<index_type, _Extents::rank()>& __idx_a, index_sequence<_Pos...>) const noexcept
{
index_type __res = 0;
((__res = __idx_a[extents_type::rank() - 1 - _Pos] + extents().extent(extents_type::rank() - 1 - _Pos) * __res),
...);
return __res;
}
[[nodiscard]] _CCCL_API constexpr index_type
__op_index(const array<index_type, extents_type::rank()>&, index_sequence<>) const noexcept
{
return 0;
}
_CCCL_TEMPLATE(class... _Indices)
_CCCL_REQUIRES((sizeof...(_Indices) == extents_type::rank())
_CCCL_AND __mdspan_detail::__all_convertible_to_index_type<index_type, _Indices...>)
[[nodiscard]] _CCCL_API constexpr index_type operator()(_Indices... __idx) const noexcept
{
// Mappings are generally meant to be used for accessing allocations and are meant to guarantee to never
// return a value exceeding required_span_size(), which is used to know how large an allocation one needs
// Thus, this is a canonical point in multi-dimensional data structures to make invalid element access checks
// However, mdspan does check this on its own, so for now we avoid double checking in hardened mode
_CCCL_ASSERT(__mdspan_detail::__is_multidimensional_index_in(extents(), __idx...),
"layout_left::mapping: out of bounds indexing");
const array<index_type, extents_type::rank()> __idx_a{static_cast<index_type>(__idx)...};
return __op_index(__idx_a, make_index_sequence<sizeof...(_Indices)>());
}
[[nodiscard]] _CCCL_API static constexpr bool is_always_unique() noexcept
{
return true;
}
[[nodiscard]] _CCCL_API static constexpr bool is_always_exhaustive() noexcept
{
return true;
}
[[nodiscard]] _CCCL_API static constexpr bool is_always_strided() noexcept
{
return true;
}
[[nodiscard]] _CCCL_API static constexpr bool is_unique() noexcept
{
return true;
}
[[nodiscard]] _CCCL_API static constexpr bool is_exhaustive() noexcept
{
return true;
}
[[nodiscard]] _CCCL_API static constexpr bool is_strided() noexcept
{
return true;
}
_CCCL_TEMPLATE(class _Extents2 = _Extents)
_CCCL_REQUIRES((_Extents2::rank() > 0))
[[nodiscard]] _CCCL_API constexpr index_type stride(rank_type __r) const noexcept
{
// While it would be caught by extents itself too, using a too large __r
// is functionally an out of bounds access on the stored information needed to compute strides
_CCCL_ASSERT(__r < extents_type::rank(), "layout_left::mapping::stride(): invalid rank index");
index_type __s = 1;
for (rank_type __i = 0; __i < __r; __i++)
{
__s *= extents().extent(__i);
}
return __s;
}
template <class _OtherExtents, class _Extents2 = _Extents>
[[nodiscard]] _CCCL_API friend constexpr auto
operator==(const mapping& __lhs, const mapping<_OtherExtents>& __rhs) noexcept
_CCCL_TRAILING_REQUIRES(bool)((_OtherExtents::rank() == _Extents2::rank()))
{
return __lhs.extents() == __rhs.extents();
}
#if _CCCL_STD_VER <= 2017
template <class _OtherExtents, class _Extents2 = _Extents>
[[nodiscard]]
_CCCL_API friend constexpr auto operator!=(const mapping& __lhs, const mapping<_OtherExtents>& __rhs) noexcept
_CCCL_TRAILING_REQUIRES(bool)((_OtherExtents::rank() == _Extents2::rank()))
{
return __lhs.extents() != __rhs.extents();
}
#endif // _CCCL_STD_VER <= 2017
};
_CCCL_END_NAMESPACE_CUDA_STD
#include <cuda/std/__cccl/epilogue.h>
#endif // _CUDA_STD___MDSPAN_LAYOUT_LEFT_H

View File

@@ -0,0 +1,288 @@
// -*- 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
// SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES.
//
// 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.
//
//===---------------------------------------------------------------------===//
#ifndef _CUDA_STD___MDSPAN_LAYOUT_RIGHT_H
#define _CUDA_STD___MDSPAN_LAYOUT_RIGHT_H
#include <cuda/std/detail/__config>
#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 <cuda/std/__concepts/concept_macros.h>
#include <cuda/std/__fwd/mdspan.h>
#include <cuda/std/__mdspan/concepts.h>
#include <cuda/std/__mdspan/empty_base.h>
#include <cuda/std/__mdspan/extents.h>
#include <cuda/std/__type_traits/fold.h>
#include <cuda/std/__type_traits/is_constructible.h>
#include <cuda/std/__type_traits/is_convertible.h>
#include <cuda/std/__type_traits/is_nothrow_constructible.h>
#include <cuda/std/__utility/integer_sequence.h>
#include <cuda/std/array>
#include <cuda/std/cstddef>
#include <cuda/std/limits>
#include <cuda/std/__cccl/prologue.h>
_CCCL_BEGIN_NAMESPACE_CUDA_STD
template <class _Extents>
class _CCCL_DECLSPEC_EMPTY_BASES layout_right::mapping : private __mdspan_ebco<_Extents>
{
public:
static_assert(__is_cuda_std_extents_v<_Extents>,
"layout_right::mapping template argument must be a specialization of extents.");
using extents_type = _Extents;
using index_type = typename extents_type::index_type;
using size_type = typename extents_type::size_type;
using rank_type = typename extents_type::rank_type;
using layout_type = layout_right;
using __base = __mdspan_ebco<_Extents>;
template <class, class, class, class>
friend class mdspan;
private:
static_assert((extents_type::rank_dynamic() > 0)
|| ::cuda::std::__mdspan_detail::__required_span_size_is_representable(extents_type()),
"layout_right::mapping product of static extents must be representable as index_type.");
public:
// [mdspan.layout.right.cons], constructors
_CCCL_HIDE_FROM_ABI constexpr mapping() noexcept = default;
_CCCL_HIDE_FROM_ABI constexpr mapping(const mapping&) noexcept = default;
_CCCL_API constexpr mapping(const extents_type& __ext) noexcept
: __base(__ext)
{
// not catching this could lead to out-of-bounds access later when used inside mdspan
// mapping<dextents<char, 2>> map(dextents<char, 2>(40,40)); map(3, 10) == -126
_CCCL_ASSERT(::cuda::std::__mdspan_detail::__required_span_size_is_representable(__ext),
"layout_right::mapping extents ctor: product of extents must be representable as index_type.");
}
_CCCL_TEMPLATE(class _OtherExtents)
_CCCL_REQUIRES(is_constructible_v<extents_type, _OtherExtents> _CCCL_AND is_convertible_v<_OtherExtents, extents_type>)
_CCCL_API constexpr mapping(const mapping<_OtherExtents>& __other) noexcept
: __base(__other.extents())
{
// not catching this could lead to out-of-bounds access later when used inside mdspan
// mapping<dextents<char, 2>> map(mapping<dextents<int, 2>>(dextents<int, 2>(40,40))); map(3, 10) == -126
_CCCL_ASSERT(::cuda::std::__mdspan_detail::__is_representable_as<index_type>(__other.required_span_size()),
"layout_right::mapping converting ctor: other.required_span_size() must be representable as "
"index_type.");
}
_CCCL_TEMPLATE(class _OtherExtents)
_CCCL_REQUIRES(
is_constructible_v<extents_type, _OtherExtents> _CCCL_AND(!is_convertible_v<_OtherExtents, extents_type>))
_CCCL_API explicit constexpr mapping(const mapping<_OtherExtents>& __other) noexcept
: __base(__other.extents())
{
// not catching this could lead to out-of-bounds access later when used inside mdspan
// mapping<dextents<char, 2>> map(mapping<dextents<int, 2>>(dextents<int, 2>(40,40))); map(3, 10) == -126
_CCCL_ASSERT(::cuda::std::__mdspan_detail::__is_representable_as<index_type>(__other.required_span_size()),
"layout_right::mapping converting ctor: other.required_span_size() must be representable as "
"index_type.");
}
_CCCL_TEMPLATE(class _OtherExtents)
_CCCL_REQUIRES((_OtherExtents::rank() <= 1) _CCCL_AND is_constructible_v<extents_type, _OtherExtents> _CCCL_AND
is_convertible_v<_OtherExtents, extents_type>)
_CCCL_API constexpr mapping(const layout_left::mapping<_OtherExtents>& __other) noexcept
: __base(__other.extents())
{
// not catching this could lead to out-of-bounds access later when used inside mdspan
// Note: since this is constraint to rank 1, extents itself would catch the invalid conversion first
// and thus this assertion should never be triggered, but keeping it here for consistency
// layout_right::mapping<dextents<char, 1>> map(
// layout_left::mapping<dextents<unsigned, 1>>(dextents<unsigned, 1>(200))); map.extents().extent(0) ==
// -56
_CCCL_ASSERT(::cuda::std::__mdspan_detail::__is_representable_as<index_type>(__other.required_span_size()),
"layout_right::mapping converting ctor: other.required_span_size() must be representable as "
"index_type.");
}
_CCCL_TEMPLATE(class _OtherExtents)
_CCCL_REQUIRES((_OtherExtents::rank() <= 1) _CCCL_AND is_constructible_v<extents_type, _OtherExtents> _CCCL_AND(
!is_convertible_v<_OtherExtents, extents_type>))
_CCCL_API explicit constexpr mapping(const layout_left::mapping<_OtherExtents>& __other) noexcept
: __base(__other.extents())
{
// not catching this could lead to out-of-bounds access later when used inside mdspan
// Note: since this is constraint to rank 1, extents itself would catch the invalid conversion first
// and thus this assertion should never be triggered, but keeping it here for consistency
// layout_right::mapping<dextents<char, 1>> map(
// layout_left::mapping<dextents<unsigned, 1>>(dextents<unsigned, 1>(200))); map.extents().extent(0) ==
// -56
_CCCL_ASSERT(::cuda::std::__mdspan_detail::__is_representable_as<index_type>(__other.required_span_size()),
"layout_right::mapping converting ctor: other.required_span_size() must be representable as "
"index_type.");
}
template <class _OtherMappping>
[[nodiscard]] _CCCL_API constexpr bool __check_strides(const _OtherMappping& __other) const noexcept
{
// avoid warning when comparing signed and unsigner integers and pick the wider of two types
using _CommonType = common_type_t<index_type, typename _OtherMappping::index_type>;
for (rank_type __r = 0; __r != extents_type::rank(); __r++)
{
if (static_cast<_CommonType>(stride(__r)) != static_cast<_CommonType>(__other.stride(__r)))
{
return false;
}
}
return true;
}
_CCCL_TEMPLATE(class _OtherExtents)
_CCCL_REQUIRES(is_constructible_v<extents_type, _OtherExtents> _CCCL_AND(extents_type::rank() > 0))
_CCCL_API explicit constexpr mapping(const layout_stride::mapping<_OtherExtents>& __other) noexcept
: __base(__other.extents())
{
_CCCL_ASSERT(__check_strides(__other),
"layout_right::mapping from layout_stride ctor: strides are not compatible with layout_left.");
_CCCL_ASSERT(::cuda::std::__mdspan_detail::__is_representable_as<index_type>(__other.required_span_size()),
"layout_right::mapping from layout_stride ctor: other.required_span_size() must be representable as "
"index_type.");
}
_CCCL_TEMPLATE(class _OtherExtents)
_CCCL_REQUIRES(is_constructible_v<extents_type, _OtherExtents> _CCCL_AND(extents_type::rank() == 0))
_CCCL_API constexpr mapping(const layout_stride::mapping<_OtherExtents>& __other) noexcept
: __base(__other.extents())
{}
_CCCL_HIDE_FROM_ABI constexpr mapping& operator=(const mapping&) noexcept = default;
// [mdspan.layout.right.obs], observers
[[nodiscard]] _CCCL_API constexpr const extents_type& extents() const noexcept
{
return this->template __get<0>();
}
[[nodiscard]] _CCCL_API constexpr index_type required_span_size() const noexcept
{
index_type __size = 1;
if constexpr (extents_type::rank() > 0) // MSVC raises a warning even with __r != extents_type::rank()
{
for (size_t __r = 0; __r < extents_type::rank(); __r++)
{
__size *= extents().extent(__r);
}
}
return __size;
}
template <size_t... _Pos, class... _Indices>
[[nodiscard]] _CCCL_API constexpr index_type __op_index(index_sequence<_Pos...>, _Indices... __idx) const noexcept
{
index_type __res = 0;
((__res = static_cast<index_type>(__idx) + extents().extent(_Pos) * __res), ...);
return __res;
}
[[nodiscard]] _CCCL_API constexpr index_type __op_index(index_sequence<>) const noexcept
{
return 0;
}
_CCCL_TEMPLATE(class... _Indices)
_CCCL_REQUIRES((sizeof...(_Indices) == extents_type::rank())
_CCCL_AND __mdspan_detail::__all_convertible_to_index_type<index_type, _Indices...>)
[[nodiscard]] _CCCL_API constexpr index_type operator()(_Indices... __idx) const noexcept
{
// Mappings are generally meant to be used for accessing allocations and are meant to guarantee to never
// return a value exceeding required_span_size(), which is used to know how large an allocation one needs
// Thus, this is a canonical point in multi-dimensional data structures to make invalid element access checks
// However, mdspan does check this on its own, so for now we avoid double checking in hardened mode
_CCCL_ASSERT(__mdspan_detail::__is_multidimensional_index_in(extents(), __idx...),
"layout_right::mapping: out of bounds indexing");
return __op_index(make_index_sequence<sizeof...(_Indices)>(), __idx...);
}
[[nodiscard]] _CCCL_API static constexpr bool is_always_unique() noexcept
{
return true;
}
[[nodiscard]] _CCCL_API static constexpr bool is_always_exhaustive() noexcept
{
return true;
}
[[nodiscard]] _CCCL_API static constexpr bool is_always_strided() noexcept
{
return true;
}
[[nodiscard]] _CCCL_API static constexpr bool is_unique() noexcept
{
return true;
}
[[nodiscard]] _CCCL_API static constexpr bool is_exhaustive() noexcept
{
return true;
}
[[nodiscard]] _CCCL_API static constexpr bool is_strided() noexcept
{
return true;
}
_CCCL_TEMPLATE(class _Extents2 = _Extents)
_CCCL_REQUIRES((_Extents2::rank() > 0))
[[nodiscard]] _CCCL_API constexpr index_type stride(rank_type __r) const noexcept
{
// While it would be caught by extents itself too, using a too large __r
// is functionally an out of bounds access on the stored information needed to compute strides
_CCCL_ASSERT(__r < extents_type::rank(), "layout_right::mapping::stride(): invalid rank index");
index_type __s = 1;
for (rank_type __i = extents_type::rank() - 1; __i > __r; __i--)
{
__s *= extents().extent(__i);
}
return __s;
}
template <class _OtherExtents, class _Extents2 = _Extents>
[[nodiscard]] _CCCL_API friend constexpr auto
operator==(const mapping& __lhs, const mapping<_OtherExtents>& __rhs) noexcept
_CCCL_TRAILING_REQUIRES(bool)((_OtherExtents::rank() == _Extents2::rank()))
{
return __lhs.extents() == __rhs.extents();
}
#if _CCCL_STD_VER <= 2017
template <class _OtherExtents, class _Extents2 = _Extents>
[[nodiscard]]
_CCCL_API friend constexpr auto operator!=(const mapping& __lhs, const mapping<_OtherExtents>& __rhs) noexcept
_CCCL_TRAILING_REQUIRES(bool)((_OtherExtents::rank() == _Extents2::rank()))
{
return __lhs.extents() != __rhs.extents();
}
#endif // _CCCL_STD_VER <= 2017
};
_CCCL_END_NAMESPACE_CUDA_STD
#include <cuda/std/__cccl/epilogue.h>
#endif // _CUDA_STD___MDSPAN_LAYOUT_RIGHT_H

View File

@@ -0,0 +1,623 @@
// -*- 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
// SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES.
//
// 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.
//
//===---------------------------------------------------------------------===//
#ifndef _CUDA_STD___MDSPAN_LAYOUT_STRIDE_H
#define _CUDA_STD___MDSPAN_LAYOUT_STRIDE_H
#include <cuda/std/detail/__config>
#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 <cuda/std/__fwd/mdspan.h>
#include <cuda/std/__mdspan/concepts.h>
#include <cuda/std/__mdspan/empty_base.h>
#include <cuda/std/__mdspan/extents.h>
#include <cuda/std/__type_traits/integral_constant.h>
#include <cuda/std/__type_traits/is_constructible.h>
#include <cuda/std/__type_traits/is_convertible.h>
#include <cuda/std/__type_traits/is_nothrow_constructible.h>
#include <cuda/std/__type_traits/is_same.h>
#include <cuda/std/__utility/as_const.h>
#include <cuda/std/__utility/integer_sequence.h>
#include <cuda/std/__utility/swap.h>
#include <cuda/std/array>
#include <cuda/std/cstddef>
#include <cuda/std/limits>
#include <cuda/std/__cccl/prologue.h>
_CCCL_BEGIN_NAMESPACE_CUDA_STD
namespace __layout_stride_detail
{
template <class _Extents, class _StrideArray, bool = (_Extents::rank() == 0)>
struct _CCCL_DECLSPEC_EMPTY_BASES __mapping_base : __mdspan_ebco<_Extents, _StrideArray>
{
using __base = __mdspan_ebco<_Extents, _StrideArray>;
using __base::__base;
};
template <class _Extents, class _StrideArray>
struct _CCCL_DECLSPEC_EMPTY_BASES __mapping_base<_Extents, _StrideArray, true> : __mdspan_ebco<_Extents>
{
using __base = __mdspan_ebco<_Extents>;
using __base::__base;
_CCCL_API constexpr __mapping_base(const _Extents& __ext,
const _StrideArray&) noexcept(is_nothrow_constructible_v<__base, const _Extents&>)
: __base(__ext)
{}
};
template <class _StridedLayoutMapping, class _Extents>
_CCCL_CONCEPT __can_convert = _CCCL_REQUIRES_EXPR((_StridedLayoutMapping, _Extents))(
requires(__mdspan_detail::__layout_mapping_alike<_StridedLayoutMapping>),
requires(_StridedLayoutMapping::is_always_unique()),
requires(_StridedLayoutMapping::is_always_strided()),
requires(is_constructible_v<_Extents, typename _StridedLayoutMapping::extents_type>));
struct __constraints
{
template <class _StridedLayoutMapping, class _Extents>
static constexpr bool __converts_implicit =
is_convertible_v<typename _StridedLayoutMapping::extents_type, _Extents>
&& (__mdspan_detail::__is_mapping_of<layout_left, _StridedLayoutMapping>
|| __mdspan_detail::__is_mapping_of<layout_right, _StridedLayoutMapping>
|| __mdspan_detail::__is_mapping_of<layout_stride, _StridedLayoutMapping>);
};
} // namespace __layout_stride_detail
template <class _Extents>
class _CCCL_DECLSPEC_EMPTY_BASES layout_stride::mapping
: private __layout_stride_detail::__mapping_base<
_Extents,
__mdspan_detail::__possibly_empty_array<typename _Extents::index_type, _Extents::rank()>>
{
public:
static_assert(__is_cuda_std_extents_v<_Extents>,
"layout_stride::mapping template argument must be a specialization of extents.");
using extents_type = _Extents;
using index_type = typename extents_type::index_type;
using size_type = typename extents_type::size_type;
using rank_type = typename extents_type::rank_type;
using layout_type = layout_stride;
using __base =
__layout_stride_detail::__mapping_base<_Extents,
__mdspan_detail::__possibly_empty_array<index_type, extents_type::rank()>>;
template <class, class, class, class>
friend class mdspan;
private:
static constexpr rank_type __rank_ = extents_type::rank();
static constexpr auto __rank_sequence = ::cuda::std::make_index_sequence<extents_type::rank()>();
using __stride_array = __mdspan_detail::__possibly_empty_array<index_type, extents_type::rank()>;
// Used for default construction check and mandates
[[nodiscard]] _CCCL_API static constexpr bool
__add_overflow(index_type __x, index_type __y, index_type* __res) noexcept
{
*__res = __x + __y;
return *__res < __y;
}
template <class _OtherIndexType>
[[nodiscard]] _CCCL_API static constexpr bool
__conversion_may_overflow([[maybe_unused]] _OtherIndexType __stride) noexcept
{
// nvcc believes stride is unused here
if constexpr (is_integral_v<_OtherIndexType>)
{
using _CommonType = common_type_t<index_type, _OtherIndexType>;
return static_cast<_CommonType>(__stride) > static_cast<_CommonType>((numeric_limits<index_type>::max)());
}
else
{
return false;
}
}
template <class _OtherIndexType>
[[nodiscard]] _CCCL_API static constexpr bool __required_span_size_is_representable(
const extents_type& __ext, [[maybe_unused]] span<_OtherIndexType, extents_type::rank()> __strides)
{
// nvcc believes strides is unused here
bool __result = true;
if constexpr (extents_type::rank() != 0)
{
index_type __size = 1;
for (rank_type __r = 0; __r != extents_type::rank(); __r++)
{
// We can only check correct conversion of _OtherIndexType if it is an integral
if (__conversion_may_overflow(__strides[__r]))
{
__result = false;
break;
}
if (__ext.extent(__r) == index_type{0})
{
__result = true;
break;
}
index_type __prod = (__ext.extent(__r) - 1);
if (::cuda::std::__mdspan_detail::__mul_overflow(__prod, static_cast<index_type>(__strides[__r]), &__prod))
{
__result = false;
break;
}
if (__add_overflow(__size, __prod, &__size))
{
__result = false;
break;
}
}
}
return __result;
}
// compute offset of a strided layout mapping
template <class _StridedMapping, size_t... _Pos>
[[nodiscard]] _CCCL_API static constexpr auto
__offset(const _StridedMapping& __mapping, index_sequence<_Pos...>) noexcept
{
return static_cast<typename _StridedMapping::index_type>(__mapping((static_cast<void>(_Pos), 0)...));
}
template <class _StridedMapping>
[[nodiscard]] _CCCL_API static constexpr index_type __offset(const _StridedMapping& __mapping)
{
using _StridedExtents = typename _StridedMapping::extents_type;
if constexpr (_StridedExtents::rank() != 0)
{
if (__mapping.required_span_size() == typename _StridedMapping::index_type{0})
{
return index_type{0};
}
return static_cast<index_type>(__offset(__mapping, __rank_sequence));
}
else
{
return static_cast<index_type>(__mapping());
}
}
static_assert((extents_type::rank_dynamic() > 0)
|| ::cuda::std::__mdspan_detail::__required_span_size_is_representable(extents_type()),
"layout_stride::mapping product of static extents must be representable as index_type.");
public:
// [mdspan.layout.stride.cons], constructors
_CCCL_API constexpr mapping() noexcept
: __base(extents_type())
{
if constexpr (extents_type::rank() > 0)
{
index_type __stride = 1;
for (rank_type __r = __rank_ - 1; __r > rank_type{0}; __r--)
{
__strides()[__r] = __stride;
__stride *= extents().extent(__r);
}
__strides()[0] = __stride;
}
}
_CCCL_HIDE_FROM_ABI constexpr mapping(const mapping&) noexcept = default;
template <class _OtherIndexType, size_t... _Pos>
[[nodiscard]] _CCCL_API static constexpr auto __to_strides_array(
[[maybe_unused]] span<_OtherIndexType, extents_type::rank()> __strides, index_sequence<_Pos...>) noexcept
{
// nvcc believes strides is unused here
return __stride_array{static_cast<index_type>(::cuda::std::as_const(__strides[_Pos]))...};
}
template <class _OtherIndexType, size_t... _Pos>
[[nodiscard]] _CCCL_API static constexpr auto __check_strides(
[[maybe_unused]] span<_OtherIndexType, extents_type::rank()> __strides, index_sequence<_Pos...>) noexcept
{
// nvcc believes strides is unused here
if constexpr (is_integral_v<_OtherIndexType>)
{
return ((__strides[_Pos] > _OtherIndexType{0}) && ... && true);
}
else
{
return ((static_cast<index_type>(__strides[_Pos]) > index_type{0}) && ... && true);
}
}
// compute the permutation for sorting the stride array
// we never actually sort the stride array
_CCCL_API constexpr void __bubble_sort_by_strides(array<rank_type, extents_type::rank()>& __permute) const noexcept
{
for (rank_type __i = __rank_ - 1; __i > 0; __i--)
{
for (rank_type __r = 0; __r < __i; __r++)
{
if (__strides()[__permute[__r]] > __strides()[__permute[__r + 1]])
{
swap(__permute[__r], __permute[__r + 1]);
}
else
{
// if two strides are the same then one of the associated extents must be 1 or 0
// both could be, but you can't have one larger than 1 come first
if ((__strides()[__permute[__r]] == __strides()[__permute[__r + 1]])
&& (extents().extent(__permute[__r]) > index_type{1}))
{
swap(__permute[__r], __permute[__r + 1]);
}
}
}
}
}
template <size_t... _Pos>
[[nodiscard]] _CCCL_API constexpr bool __check_unique_mapping(index_sequence<_Pos...>) const noexcept
{
// basically sort the dimensions based on strides and extents, sorting is represented in permute array
array<rank_type, extents_type::rank()> __permute{_Pos...};
__bubble_sort_by_strides(__permute);
// check that this permutations represents a growing set
bool __result = true;
for (rank_type __i = 1; __i < __rank_; __i++)
{
if (static_cast<index_type>(__strides()[__permute[__i]])
< static_cast<index_type>(__strides()[__permute[__i - 1]]) * extents().extent(__permute[__i - 1]))
{
__result = false;
break;
}
}
return __result;
}
[[nodiscard]] _CCCL_API constexpr bool __check_unique_mapping(index_sequence<>) const noexcept
{
return true;
}
// nvcc cannot deduce this constructor when using _CCCL_REQUIRES
template <class _OtherIndexType,
enable_if_t<is_constructible_v<index_type, const _OtherIndexType&>, int> = 0,
enable_if_t<is_convertible_v<const _OtherIndexType&, index_type>, int> = 0>
_CCCL_API constexpr mapping(const extents_type& __ext, span<_OtherIndexType, extents_type::rank()> __strides) noexcept
: __base(__ext, __to_strides_array(__strides, __rank_sequence))
{
_CCCL_ASSERT(__check_strides(__strides, __rank_sequence),
"layout_stride::mapping ctor: all strides must be greater than 0");
_CCCL_ASSERT(__required_span_size_is_representable(__ext, __strides),
"layout_stride::mapping ctor: required span size is not representable as index_type.");
_CCCL_ASSERT(__check_unique_mapping(__rank_sequence),
"layout_stride::mapping ctor: the provided extents and strides lead to a non-unique mapping");
}
// nvcc cannot deduce this constructor when using _CCCL_REQUIRES
template <class _OtherIndexType,
enable_if_t<is_constructible_v<index_type, const _OtherIndexType&>, int> = 0,
enable_if_t<is_convertible_v<const _OtherIndexType&, index_type>, int> = 0>
_CCCL_API constexpr mapping(const extents_type& __ext,
const array<_OtherIndexType, extents_type::rank()>& __strides) noexcept
: mapping(__ext, span<const _OtherIndexType, extents_type::rank()>(__strides))
{}
template <class _StridedLayoutMapping, size_t... _Pos>
[[nodiscard]] _CCCL_API static constexpr auto
__to_strides_array(const _StridedLayoutMapping& __other, index_sequence<_Pos...>) noexcept
{
return __stride_array{static_cast<index_type>(__other.stride(_Pos))...};
}
// stride() only compiles for rank > 0
template <class _StridedLayoutMapping, size_t... _Pos>
[[nodiscard]] _CCCL_API static constexpr auto
__check_mapped_strides(const _StridedLayoutMapping& __other, index_sequence<_Pos...>) noexcept
{
return ((static_cast<index_type>(__other.stride(_Pos)) > index_type{0}) && ... && true);
}
template <class _StridedLayoutMapping>
[[nodiscard]] _CCCL_API static constexpr auto
__check_mapped_strides(const _StridedLayoutMapping&, index_sequence<>) noexcept
{
return true;
}
_CCCL_TEMPLATE(class _StridedLayoutMapping)
_CCCL_REQUIRES(__layout_stride_detail::__can_convert<_StridedLayoutMapping, _Extents> _CCCL_AND
__layout_stride_detail::__constraints::__converts_implicit<_StridedLayoutMapping, _Extents>)
_CCCL_API constexpr mapping(const _StridedLayoutMapping& __other) noexcept
: __base(extents_type(__other.extents()), __to_strides_array(__other, __rank_sequence))
{
_CCCL_ASSERT(__check_mapped_strides(__other, __rank_sequence),
"layout_stride::mapping converting ctor: all strides must be greater than 0");
_CCCL_ASSERT(::cuda::std::__mdspan_detail::__is_representable_as<index_type>(__other.required_span_size()),
"layout_stride::mapping converting ctor: other.required_span_size() must be representable as "
"index_type.");
_CCCL_ASSERT(index_type{0} == __offset(__other),
"layout_stride::mapping converting ctor: base offset of mapping must be zero.");
}
_CCCL_TEMPLATE(class _StridedLayoutMapping)
_CCCL_REQUIRES(__layout_stride_detail::__can_convert<_StridedLayoutMapping, _Extents> _CCCL_AND(
!__layout_stride_detail::__constraints::__converts_implicit<_StridedLayoutMapping, _Extents>))
_CCCL_API explicit constexpr mapping(const _StridedLayoutMapping& __other) noexcept
: __base(extents_type(__other.extents()), __to_strides_array(__other, __rank_sequence))
{
_CCCL_ASSERT(__check_mapped_strides(__other, __rank_sequence),
"layout_stride::mapping converting ctor: all strides must be greater than 0");
_CCCL_ASSERT(::cuda::std::__mdspan_detail::__is_representable_as<index_type>(__other.required_span_size()),
"layout_stride::mapping converting ctor: other.required_span_size() must be representable as "
"index_type.");
_CCCL_ASSERT(index_type{0} == __offset(__other),
"layout_stride::mapping converting ctor: base offset of mapping must be zero.");
}
_CCCL_HIDE_FROM_ABI constexpr mapping& operator=(const mapping&) noexcept = default;
// [mdspan.layout.stride.obs], observers
[[nodiscard]] _CCCL_API constexpr const extents_type& extents() const noexcept
{
return this->template __get<0>();
}
[[nodiscard]] _CCCL_API constexpr __stride_array& __strides() noexcept
{
return this->template __get<1>();
}
[[nodiscard]] _CCCL_API constexpr const __stride_array& __strides() const noexcept
{
return this->template __get<1>();
}
template <size_t... _Pos>
_CCCL_API constexpr array<index_type, extents_type::rank()> __to_strides(index_sequence<_Pos...>) const noexcept
{
return array<index_type, extents_type::rank()>{__strides()[_Pos]...};
}
[[nodiscard]] _CCCL_API constexpr array<index_type, extents_type::rank()> strides() const noexcept
{
return __to_strides(__rank_sequence);
}
template <size_t... _Pos>
[[nodiscard]] _CCCL_API constexpr index_type __required_span_size(index_sequence<_Pos...>) const noexcept
{
const index_type __product = (index_type{1} * ... * extents().extent(_Pos));
if (__product == index_type{0})
{
return index_type{0};
}
else
{
return (index_type{1} + ... + ((extents().extent(_Pos) - index_type{1}) * __strides()[_Pos]));
}
}
[[nodiscard]] _CCCL_API constexpr index_type required_span_size() const noexcept
{
if constexpr (extents_type::rank() == 0)
{
return index_type{1};
}
else
{
return __required_span_size(__rank_sequence);
}
}
template <size_t... _Pos, class... _Indices>
[[nodiscard]] _CCCL_API static constexpr index_type
__op_index(const __stride_array& __strides, index_sequence<_Pos...>, _Indices... __idx) noexcept
{
return (index_type{0} + ... + (static_cast<index_type>(__idx) * __strides[_Pos]));
}
_CCCL_TEMPLATE(class... _Indices)
_CCCL_REQUIRES((sizeof...(_Indices) == extents_type::rank())
_CCCL_AND __mdspan_detail::__all_convertible_to_index_type<index_type, _Indices...>)
[[nodiscard]] _CCCL_API constexpr index_type operator()(_Indices... __idx) const noexcept
{
// Mappings are generally meant to be used for accessing allocations and are meant to guarantee to never
// return a value exceeding required_span_size(), which is used to know how large an allocation one needs
// Thus, this is a canonical point in multi-dimensional data structures to make invalid element access checks
// However, mdspan does check this on its own, so for now we avoid double checking in hardened mode
//_CCCL_ASSERT(__mdspan_detail::__is_multidimensional_index_in(__extents_, __idx...),
// "layout_stride::mapping: out of bounds indexing");
if constexpr (extents_type::rank() == 0)
{
return index_type{0};
}
else
{
return __op_index(__strides(), ::cuda::std::make_index_sequence<sizeof...(_Indices)>(), __idx...);
}
}
[[nodiscard]] _CCCL_API static constexpr bool is_always_unique() noexcept
{
return true;
}
[[nodiscard]] _CCCL_API static constexpr bool is_always_exhaustive() noexcept
{
return false;
}
[[nodiscard]] _CCCL_API static constexpr bool is_always_strided() noexcept
{
return true;
}
[[nodiscard]] _CCCL_API static constexpr bool is_unique() noexcept
{
return true;
}
// The answer of this function is fairly complex in the case where one or more
// extents are zero.
// Technically it is meaningless to query is_exhaustive() in that case, but unfortunately
// the way the standard defines this function, we can't give a simple true or false then.
template <size_t... _Pos>
[[nodiscard]] _CCCL_API constexpr index_type __to_total_size(index_sequence<_Pos...>) const noexcept
{
return (index_type{1} * ... * (extents().extent(_Pos)));
}
[[nodiscard]] _CCCL_API constexpr bool is_exhaustive() const noexcept
{
if constexpr (extents_type::rank() == 0)
{
return true;
}
else
{
const index_type __span_size = required_span_size();
if (__span_size == index_type{0})
{
if constexpr (extents_type::rank() == 1)
{
return __strides()[0] == 1;
}
else
{
rank_type __r_largest = 0;
for (rank_type __r = 1; __r < __rank_; __r++)
{
if (__strides()[__r] > __strides()[__r_largest])
{
__r_largest = __r;
}
}
bool __result = true;
for (rank_type __r = 0; __r != __rank_; __r++)
{
if (extents().extent(__r) == 0 && __r != __r_largest)
{
__result = false;
break;
}
}
return __result;
}
}
else
{
const index_type __total_size = __to_total_size(__rank_sequence);
return __span_size == __total_size;
}
}
}
[[nodiscard]] _CCCL_API static constexpr bool is_strided() noexcept
{
return true;
}
// according to the standard layout_stride does not have a constraint on stride(r) for rank>0
// it still has the precondition though
[[nodiscard]] _CCCL_API constexpr index_type stride(rank_type __r) const noexcept
{
if constexpr (__rank_ > 0) // avoid pointless comparison of unsigned integer with zero warning
{
_CCCL_ASSERT(__r < __rank_, "layout_stride::mapping::stride(): invalid rank index");
return __strides()[__r];
}
else
{
return index_type{0};
}
}
template <class _OtherMapping, size_t... _Pos>
[[nodiscard]] _CCCL_API static constexpr bool
__op_eq(const mapping& __lhs, const _OtherMapping& __rhs, index_sequence<_Pos...>) noexcept
{
// avoid warning when comparing signed and unsigner integers and pick the wider of two types
using _CommonType = common_type_t<index_type, typename _OtherMapping::index_type>;
return ((static_cast<_CommonType>(__lhs.stride(_Pos)) == static_cast<_CommonType>(__rhs.stride(_Pos))) && ...
&& true);
}
template <class _OtherMapping>
[[nodiscard]] _CCCL_API static constexpr bool __op_eq(const mapping& __lhs, const _OtherMapping& __rhs) noexcept
{
if constexpr (extents_type::rank() > 0)
{
if (__offset(__rhs))
{
return false;
}
return __lhs.extents() == __rhs.extents() && __op_eq(__lhs, __rhs, __rank_sequence);
}
else
{
return (!__offset(__rhs));
}
}
template <class _OtherMapping, class _OtherExtents = typename _OtherMapping::extents_type>
static constexpr bool __can_compare =
__mdspan_detail::__layout_mapping_alike<_OtherMapping> && (_OtherExtents::rank() == _Extents::rank())
&& _OtherMapping::is_always_strided();
template <class _OtherMapping>
[[nodiscard]] _CCCL_API friend constexpr auto operator==(const mapping& __lhs, const _OtherMapping& __rhs) noexcept
_CCCL_TRAILING_REQUIRES(bool)(__can_compare<_OtherMapping>)
{
return __op_eq(__lhs, __rhs);
}
#if _CCCL_STD_VER <= 2017
template <class _OtherMapping>
[[nodiscard]] _CCCL_API friend constexpr auto operator==(const _OtherMapping& __lhs, const mapping& __rhs) noexcept
_CCCL_TRAILING_REQUIRES(bool)((!__mdspan_detail::__is_mapping_of<layout_stride, _OtherMapping>)
&& __can_compare<_OtherMapping>)
{
return __op_eq(__rhs, __lhs);
}
template <class _OtherMapping, class _Extents2 = _Extents>
[[nodiscard]] _CCCL_API friend constexpr auto operator!=(const mapping& __lhs, const _OtherMapping& __rhs) noexcept
_CCCL_TRAILING_REQUIRES(bool)(__can_compare<_OtherMapping>)
{
return !__op_eq(__lhs, __rhs);
}
template <class _OtherMapping, class _Extents2 = _Extents>
[[nodiscard]] _CCCL_API friend constexpr auto operator!=(const _OtherMapping& __lhs, const mapping& __rhs) noexcept
_CCCL_TRAILING_REQUIRES(bool)((!__mdspan_detail::__is_mapping_of<layout_stride, _OtherMapping>)
&& __can_compare<_OtherMapping>)
{
return __op_eq(__rhs, __lhs);
}
#endif // _CCCL_STD_VER <= 2017
};
_CCCL_END_NAMESPACE_CUDA_STD
#include <cuda/std/__cccl/epilogue.h>
#endif // _CUDA_STD___MDSPAN_LAYOUT_STRIDE_H

View File

@@ -0,0 +1,593 @@
// -*- 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
// SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES.
//
// 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.
//
//===---------------------------------------------------------------------===//
#ifndef _CUDA_STD___MDSPAN_MDSPAN_H
#define _CUDA_STD___MDSPAN_MDSPAN_H
#include <cuda/std/detail/__config>
#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 <cuda/std/__concepts/concept_macros.h>
#include <cuda/std/__fwd/mdspan.h>
#include <cuda/std/__mdspan/concepts.h>
#include <cuda/std/__mdspan/default_accessor.h>
#include <cuda/std/__mdspan/empty_base.h>
#include <cuda/std/__mdspan/extents.h>
#include <cuda/std/__mdspan/layout_right.h>
#include <cuda/std/__type_traits/extent.h>
#include <cuda/std/__type_traits/is_abstract.h>
#include <cuda/std/__type_traits/is_array.h>
#include <cuda/std/__type_traits/is_constructible.h>
#include <cuda/std/__type_traits/is_convertible.h>
#include <cuda/std/__type_traits/is_default_constructible.h>
#include <cuda/std/__type_traits/is_nothrow_constructible.h>
#include <cuda/std/__type_traits/is_nothrow_default_constructible.h>
#include <cuda/std/__type_traits/is_pointer.h>
#include <cuda/std/__type_traits/is_same.h>
#include <cuda/std/__type_traits/rank.h>
#include <cuda/std/__type_traits/remove_all_extents.h>
#include <cuda/std/__type_traits/remove_cv.h>
#include <cuda/std/__type_traits/remove_pointer.h>
#include <cuda/std/__type_traits/remove_reference.h>
#include <cuda/std/__utility/as_const.h>
#include <cuda/std/__utility/cmp.h>
#include <cuda/std/__utility/declval.h>
#include <cuda/std/__utility/integer_sequence.h>
#include <cuda/std/__utility/move.h>
#include <cuda/std/array>
#include <cuda/std/cstddef>
#include <cuda/std/limits>
#include <cuda/std/span>
#include <cuda/std/__cccl/prologue.h>
_CCCL_BEGIN_NAMESPACE_CUDA_STD
template <class _Extents, class _LayoutPolicy, class _AccessorPolicy>
struct __mdspan_constraints
{
using extents_type = _Extents;
using layout_type = _LayoutPolicy;
using accessor_type = _AccessorPolicy;
using mapping_type = typename layout_type::template mapping<extents_type>;
using index_type = typename extents_type::index_type;
using data_handle_type = typename accessor_type::data_handle_type;
static constexpr bool __can_default_construct =
(_Extents::rank_dynamic() > 0) && is_default_constructible_v<data_handle_type>
&& is_default_constructible_v<mapping_type> && is_default_constructible_v<accessor_type>;
template <class... _OtherIndexTypes>
static constexpr bool __can_construct_from_handle_and_variadic =
(__mdspan_detail::__matches_dynamic_rank<extents_type, sizeof...(_OtherIndexTypes)>
|| __mdspan_detail::__matches_static_rank<extents_type, sizeof...(_OtherIndexTypes)>)
&& __mdspan_detail::__all_convertible_to_index_type<index_type, _OtherIndexTypes...>
&& is_constructible_v<mapping_type, extents_type> && is_default_constructible_v<accessor_type>;
template <class _OtherIndexType>
static constexpr bool __is_constructible_from_index_type =
is_convertible_v<const _OtherIndexType&, index_type>
&& is_nothrow_constructible_v<index_type, const _OtherIndexType&> && is_constructible_v<mapping_type, extents_type>
&& is_default_constructible_v<accessor_type>;
template <class _OtherExtents, class _OtherLayoutPolicy, class _OtherAccessor>
static constexpr bool __is_convertible_from =
is_constructible_v<mapping_type, const typename _OtherLayoutPolicy::template mapping<_OtherExtents>&>
&& is_constructible_v<accessor_type, const _OtherAccessor&>;
template <class _OtherExtents, class _OtherLayoutPolicy, class _OtherAccessor>
static constexpr bool __is_implicit_convertible_from =
is_convertible_v<const typename _OtherLayoutPolicy::template mapping<_OtherExtents>&, mapping_type>
&& is_convertible_v<const _OtherAccessor&, accessor_type>;
};
template <class _ElementType, class _Extents, class _LayoutPolicy, class _AccessorPolicy>
class mdspan
: private __mdspan_ebco<typename _AccessorPolicy::data_handle_type,
typename _LayoutPolicy::template mapping<_Extents>,
_AccessorPolicy>
{
private:
static_assert(__is_cuda_std_extents_v<_Extents>,
"mdspan: Extents template parameter must be a specialization of extents.");
static_assert(!is_array_v<_ElementType>, "mdspan: ElementType template parameter may not be an array type");
static_assert(!is_abstract_v<_ElementType>, "mdspan: ElementType template parameter may not be an abstract class");
static_assert(is_same_v<_ElementType, typename _AccessorPolicy::element_type>,
"mdspan: ElementType template parameter must match AccessorPolicy::element_type");
static_assert(__mdspan_detail::__is_valid_layout_mapping<_LayoutPolicy, _Extents>,
"mdspan: LayoutPolicy template parameter is invalid. A common mistake is to pass a layout mapping "
"instead of a layout policy");
template <class, class, class, class>
friend class mdspan;
using __constraints = __mdspan_constraints<_Extents, _LayoutPolicy, _AccessorPolicy>;
public:
using extents_type = _Extents;
using layout_type = _LayoutPolicy;
using accessor_type = _AccessorPolicy;
using mapping_type = typename layout_type::template mapping<extents_type>;
using element_type = _ElementType;
using value_type = remove_cv_t<element_type>;
using index_type = typename extents_type::index_type;
using size_type = typename extents_type::size_type;
using rank_type = typename extents_type::rank_type;
using data_handle_type = typename accessor_type::data_handle_type;
using reference = typename accessor_type::reference;
using __base = __mdspan_ebco<typename accessor_type::data_handle_type,
typename _LayoutPolicy::template mapping<_Extents>,
_AccessorPolicy>;
[[nodiscard]] _CCCL_API static constexpr rank_type rank() noexcept
{
return extents_type::rank();
}
[[nodiscard]] _CCCL_API static constexpr rank_type rank_dynamic() noexcept
{
return extents_type::rank_dynamic();
}
[[nodiscard]] _CCCL_API static constexpr size_t static_extent(rank_type __r) noexcept
{
return extents_type::static_extent(__r);
}
[[nodiscard]] _CCCL_API constexpr index_type extent(rank_type __r) const noexcept
{
return mapping().extents().extent(__r);
}
//--------------------------------------------------------------------------------
// [mdspan.mdspan.cons], mdspan constructors, assignment, and destructor
_CCCL_TEMPLATE(class _Extents2 = _Extents)
_CCCL_REQUIRES(__mdspan_constraints<_Extents2, _LayoutPolicy, _AccessorPolicy>::__can_default_construct)
_CCCL_API constexpr mdspan() noexcept(
is_nothrow_default_constructible_v<data_handle_type> && is_nothrow_default_constructible_v<mapping_type>
&& is_nothrow_default_constructible_v<accessor_type>)
: __base()
{
if constexpr (::cuda::std::__has_detect_invalidity<accessor_type>)
{
[[maybe_unused]] const auto& __tmp = mapping(); // workaround for clang with nodiscard
_CCCL_ASSERT(!accessor().__detectably_invalid(data_handle(), __tmp.required_span_size()),
"mdspan: invalid data handle");
}
}
_CCCL_HIDE_FROM_ABI constexpr mdspan(const mdspan&) = default;
_CCCL_HIDE_FROM_ABI constexpr mdspan(mdspan&&) = default;
_CCCL_TEMPLATE(class... _OtherIndexTypes)
_CCCL_REQUIRES(__constraints::template __can_construct_from_handle_and_variadic<_OtherIndexTypes...>)
_CCCL_API explicit constexpr mdspan(data_handle_type __p, _OtherIndexTypes... __exts)
: __base(::cuda::std::move(__p), extents_type(static_cast<index_type>(::cuda::std::move(__exts))...))
{
if constexpr (::cuda::std::__has_detect_invalidity<accessor_type>)
{
[[maybe_unused]] const auto& __tmp = mapping(); // workaround for clang with nodiscard
_CCCL_ASSERT(!accessor().__detectably_invalid(data_handle(), __tmp.required_span_size()),
"mdspan: invalid data handle");
}
}
_CCCL_TEMPLATE(class _OtherIndexType, size_t _Size)
_CCCL_REQUIRES(__mdspan_detail::__matches_dynamic_rank<extents_type, _Size> _CCCL_AND
__constraints::template __is_constructible_from_index_type<_OtherIndexType>)
_CCCL_API constexpr mdspan(data_handle_type __p, const array<_OtherIndexType, _Size>& __exts)
: __base(::cuda::std::move(__p), extents_type{__exts})
{
if constexpr (::cuda::std::__has_detect_invalidity<accessor_type>)
{
[[maybe_unused]] const auto& __tmp = mapping(); // workaround for clang with nodiscard
_CCCL_ASSERT(!accessor().__detectably_invalid(data_handle(), __tmp.required_span_size()),
"mdspan: invalid data handle");
}
}
_CCCL_TEMPLATE(class _OtherIndexType, size_t _Size)
_CCCL_REQUIRES(__mdspan_detail::__matches_static_rank<extents_type, _Size> _CCCL_AND
__constraints::template __is_constructible_from_index_type<_OtherIndexType>)
_CCCL_API explicit constexpr mdspan(data_handle_type __p, const array<_OtherIndexType, _Size>& __exts)
: __base(::cuda::std::move(__p), extents_type{__exts})
{
if constexpr (::cuda::std::__has_detect_invalidity<accessor_type>)
{
[[maybe_unused]] const auto& __tmp = mapping(); // workaround for clang with nodiscard
_CCCL_ASSERT(!accessor().__detectably_invalid(data_handle(), __tmp.required_span_size()),
"mdspan: invalid data handle");
}
}
_CCCL_TEMPLATE(class _OtherIndexType, size_t _Size)
_CCCL_REQUIRES(__mdspan_detail::__matches_dynamic_rank<extents_type, _Size> _CCCL_AND
__constraints::template __is_constructible_from_index_type<_OtherIndexType>)
_CCCL_API constexpr mdspan(data_handle_type __p, span<_OtherIndexType, _Size> __exts)
: __base(::cuda::std::move(__p), extents_type{__exts})
{
if constexpr (::cuda::std::__has_detect_invalidity<accessor_type>)
{
[[maybe_unused]] const auto& __tmp = mapping(); // workaround for clang with nodiscard
_CCCL_ASSERT(!accessor().__detectably_invalid(data_handle(), __tmp.required_span_size()),
"mdspan: invalid data handle");
}
}
_CCCL_TEMPLATE(class _OtherIndexType, size_t _Size)
_CCCL_REQUIRES(__mdspan_detail::__matches_static_rank<extents_type, _Size> _CCCL_AND
__constraints::template __is_constructible_from_index_type<_OtherIndexType>)
_CCCL_API explicit constexpr mdspan(data_handle_type __p, span<_OtherIndexType, _Size> __exts)
: __base(::cuda::std::move(__p), extents_type{__exts})
{
if constexpr (::cuda::std::__has_detect_invalidity<accessor_type>)
{
[[maybe_unused]] const auto& __tmp = mapping(); // workaround for clang with nodiscard
_CCCL_ASSERT(!accessor().__detectably_invalid(data_handle(), __tmp.required_span_size()),
"mdspan: invalid data handle");
}
}
_CCCL_TEMPLATE(class _AccessorPolicy2 = _AccessorPolicy, class _Mapping2 = mapping_type)
_CCCL_REQUIRES(
is_default_constructible_v<_AccessorPolicy2> _CCCL_AND is_constructible_v<_Mapping2, const extents_type&>)
_CCCL_API constexpr mdspan(data_handle_type __p, const extents_type& __exts)
: __base(::cuda::std::move(__p), __exts)
{
if constexpr (::cuda::std::__has_detect_invalidity<accessor_type>)
{
[[maybe_unused]] const auto& __tmp = mapping(); // workaround for clang with nodiscard
_CCCL_ASSERT(!accessor().__detectably_invalid(data_handle(), __tmp.required_span_size()),
"mdspan: invalid data handle");
}
}
_CCCL_TEMPLATE(class _AccessorPolicy2 = _AccessorPolicy)
_CCCL_REQUIRES(is_default_constructible_v<_AccessorPolicy2>)
_CCCL_API constexpr mdspan(data_handle_type __p, const mapping_type& __m)
: __base(::cuda::std::move(__p), __m)
{
if constexpr (::cuda::std::__has_detect_invalidity<accessor_type>)
{
[[maybe_unused]] const auto& __tmp = mapping(); // workaround for clang with nodiscard
_CCCL_ASSERT(!accessor().__detectably_invalid(data_handle(), __tmp.required_span_size()),
"mdspan: invalid data handle");
}
}
_CCCL_API constexpr mdspan(data_handle_type __p, const mapping_type& __m, const accessor_type& __a)
: __base(::cuda::std::move(__p), __m, __a)
{
if constexpr (::cuda::std::__has_detect_invalidity<accessor_type>)
{
[[maybe_unused]] const auto& __tmp = mapping(); // workaround for clang with nodiscard
_CCCL_ASSERT(!accessor().__detectably_invalid(data_handle(), __tmp.required_span_size()),
"mdspan: invalid data handle");
}
}
_CCCL_TEMPLATE(class _OtherElementType, class _OtherExtents, class _OtherLayoutPolicy, class _OtherAccessor)
_CCCL_REQUIRES(
__constraints::template __is_convertible_from<_OtherExtents, _OtherLayoutPolicy, _OtherAccessor> //
_CCCL_AND
__constraints::template __is_implicit_convertible_from<_OtherExtents, _OtherLayoutPolicy, _OtherAccessor>)
_CCCL_API constexpr mdspan(const mdspan<_OtherElementType, _OtherExtents, _OtherLayoutPolicy, _OtherAccessor>& __other)
: __base(__other.data_handle(), __other.mapping(), __other.accessor())
{
static_assert(is_constructible_v<data_handle_type, const typename _OtherAccessor::data_handle_type&>,
"mdspan: incompatible data_handle_type for mdspan construction");
static_assert(is_constructible_v<extents_type, _OtherExtents>,
"mdspan: incompatible extents for mdspan construction");
if constexpr (::cuda::std::__has_detect_invalidity<accessor_type>)
{
[[maybe_unused]] const auto& __tmp = mapping(); // workaround for clang with nodiscard
_CCCL_ASSERT(!accessor().__detectably_invalid(data_handle(), __tmp.required_span_size()),
"mdspan: invalid data handle");
}
if constexpr (extents_type::rank() != 0)
{
// The following precondition is part of the standard, but is unlikely to be triggered.
// The extents constructor checks this and the mapping must be storing the extents, since
// its extents() function returns a const reference to extents_type.
// The only way this can be triggered is if the mapping conversion constructor would for example
// always construct its extents() only from the dynamic extents, instead of from the other extents.
for (size_t __r = 0; __r != extents_type::rank(); __r++)
{
// Not catching this could lead to out of bounds errors later
// e.g. mdspan<int, dextents<char,1>, non_checking_layout> m =
// mdspan<int, dextents<unsigned, 1>, non_checking_layout>(ptr, 200); leads to an extent of -56 on m
_CCCL_ASSERT(
(static_extent(__r) == dynamic_extent) || ::cuda::std::cmp_equal(__other.extent(__r), static_extent(__r)),
"mdspan: conversion mismatch of source dynamic extents with static extents");
}
}
}
_CCCL_TEMPLATE(class _OtherElementType, class _OtherExtents, class _OtherLayoutPolicy, class _OtherAccessor)
_CCCL_REQUIRES(
__constraints::template __is_convertible_from<_OtherExtents, _OtherLayoutPolicy, _OtherAccessor> _CCCL_AND(
!__constraints::template __is_implicit_convertible_from<_OtherExtents, _OtherLayoutPolicy, _OtherAccessor>))
_CCCL_API explicit constexpr mdspan(
const mdspan<_OtherElementType, _OtherExtents, _OtherLayoutPolicy, _OtherAccessor>& __other)
: __base(__other.data_handle(), __other.mapping(), __other.accessor())
{
static_assert(is_constructible_v<data_handle_type, const typename _OtherAccessor::data_handle_type&>,
"mdspan: incompatible data_handle_type for mdspan construction");
static_assert(is_constructible_v<extents_type, _OtherExtents>,
"mdspan: incompatible extents for mdspan construction");
if constexpr (::cuda::std::__has_detect_invalidity<accessor_type>)
{
[[maybe_unused]] const auto& __tmp = mapping(); // workaround for clang with nodiscard
_CCCL_ASSERT(!accessor().__detectably_invalid(data_handle(), __tmp.required_span_size()),
"mdspan: invalid data handle");
}
if constexpr (extents_type::rank() != 0)
{
// The following precondition is part of the standard, but is unlikely to be triggered.
// The extents constructor checks this and the mapping must be storing the extents, since
// its extents() function returns a const reference to extents_type.
// The only way this can be triggered is if the mapping conversion constructor would for example
// always construct its extents() only from the dynamic extents, instead of from the other extents.
for (size_t __r = 0; __r < extents_type::rank(); __r++)
{
// Not catching this could lead to out of bounds errors later
// e.g. mdspan<int, dextents<char,1>, non_checking_layout> m =
// mdspan<int, dextents<unsigned, 1>, non_checking_layout>(ptr, 200); leads to an extent of -56 on m
_CCCL_ASSERT(
(static_extent(__r) == dynamic_extent) || ::cuda::std::cmp_equal(__other.extent(__r), static_extent(__r)),
"mdspan: conversion mismatch of source dynamic extents with static extents");
}
}
}
_CCCL_HIDE_FROM_ABI constexpr mdspan& operator=(const mdspan&) = default;
_CCCL_HIDE_FROM_ABI constexpr mdspan& operator=(mdspan&&) = default;
//--------------------------------------------------------------------------------
// [mdspan.mdspan.members], members
#if _CCCL_HAS_MULTIARG_OPERATOR_BRACKETS()
_CCCL_TEMPLATE(class... _OtherIndexTypes)
_CCCL_REQUIRES((sizeof...(_OtherIndexTypes) == extents_type::rank())
_CCCL_AND __mdspan_detail::__all_convertible_to_index_type<index_type, _OtherIndexTypes...>)
[[nodiscard]] _CCCL_API constexpr reference operator[](_OtherIndexTypes... __indices) const
{
// Note the standard layouts would also check this, but user provided ones may not, so we
// check the precondition here
_CCCL_ASSERT(__mdspan_detail::__is_multidimensional_index_in(extents(), __indices...),
"mdspan: operator[] out of bounds access");
return accessor().access(data_handle(), mapping()(static_cast<index_type>(::cuda::std::move(__indices))...));
}
#else
_CCCL_TEMPLATE(class _OtherIndexType)
_CCCL_REQUIRES((extents_type::rank() == 1) _CCCL_AND is_convertible_v<_OtherIndexType, index_type> _CCCL_AND
is_nothrow_constructible_v<index_type, _OtherIndexType>)
[[nodiscard]] _CCCL_API constexpr reference operator[](_OtherIndexType __index) const
{
return accessor().access(data_handle(), mapping()(static_cast<index_type>(::cuda::std::move(__index))));
}
#endif // _CCCL_HAS_MULTIARG_OPERATOR_BRACKETS
template <class _OtherIndexType, size_t... _Idxs>
[[nodiscard]] _CCCL_API constexpr decltype(auto)
__op_bracket(const array<_OtherIndexType, _Extents::rank()>& __indices, index_sequence<_Idxs...>) const noexcept
{
// Note the standard layouts would also check this, but user provided ones may not, so we
// check the precondition here
_CCCL_ASSERT(__mdspan_detail::__is_multidimensional_index_in(extents(), __indices[_Idxs]...),
"mdspan: operator[array] out of bounds access");
return mapping()(__indices[_Idxs]...);
}
template <class _OtherIndexType, size_t... _Idxs>
[[nodiscard]] _CCCL_API constexpr decltype(auto)
__op_bracket(span<_OtherIndexType, _Extents::rank()> __indices, index_sequence<_Idxs...>) const noexcept
{
// Note the standard layouts would also check this, but user provided ones may not, so we
// check the precondition here
_CCCL_ASSERT(__mdspan_detail::__is_multidimensional_index_in(extents(), __indices[_Idxs]...),
"mdspan: operator[span] out of bounds access");
return mapping()(__indices[_Idxs]...);
}
_CCCL_TEMPLATE(class _OtherIndexType)
_CCCL_REQUIRES(is_convertible_v<const _OtherIndexType&, index_type> _CCCL_AND
is_nothrow_constructible_v<index_type, const _OtherIndexType&>)
[[nodiscard]] _CCCL_API constexpr reference
operator[](const array<_OtherIndexType, extents_type::rank()>& __indices) const
{
return accessor().access(data_handle(), __op_bracket(__indices, make_index_sequence<rank()>()));
}
_CCCL_TEMPLATE(class _OtherIndexType)
_CCCL_REQUIRES(is_convertible_v<const _OtherIndexType&, index_type> _CCCL_AND
is_nothrow_constructible_v<index_type, const _OtherIndexType&>)
[[nodiscard]] _CCCL_API constexpr reference operator[](span<_OtherIndexType, extents_type::rank()> __indices) const
{
return accessor().access(data_handle(), __op_bracket(__indices, make_index_sequence<rank()>()));
}
//! Nonstandard extension to no break our users too hard
_CCCL_TEMPLATE(class... _Indices)
_CCCL_REQUIRES(__mdspan_detail::__all_convertible_to_index_type<index_type, _Indices...>)
[[nodiscard]] _CCCL_API constexpr reference operator()(_Indices... __indices) const
{
// Note the standard layouts would also check this, but user provided ones may not, so we
// check the precondition here
_CCCL_ASSERT(__mdspan_detail::__is_multidimensional_index_in(extents(), __indices...),
"mdspan: operator() out of bounds access");
return accessor().access(data_handle(), mapping()(__indices...));
}
template <size_t... _Idxs>
[[nodiscard]] _CCCL_API constexpr bool __check_size() const noexcept
{
bool __result = true;
if constexpr (extents_type::rank() > 0) // MSVC raises a warning even with __r != extents_type::rank()
{
size_t __prod = 1;
for (size_t __r = 0; __r < extents_type::rank(); ++__r)
{
const auto __extent = static_cast<size_t>(mapping().extents().extent(__r));
if (__mdspan_detail::__mul_overflow(__prod, __extent, &__prod))
{
__result = false;
break;
}
}
}
return __result;
}
template <size_t... _Idxs>
[[nodiscard]] _CCCL_API constexpr size_type __op_size(index_sequence<_Idxs...>) const noexcept
{
return (size_type{1} * ... * static_cast<size_type>(mapping().extents().extent(_Idxs)));
}
[[nodiscard]] _CCCL_API constexpr size_type size() const noexcept
{
// Could leave this as only checked in debug mode: semantically size() is never
// guaranteed to be related to any accessible range
_CCCL_ASSERT(__check_size(), "mdspan: size() is not representable as size_type");
return __op_size(make_index_sequence<rank()>());
}
template <size_t... _Idxs>
[[nodiscard]] _CCCL_API constexpr bool __op_empty(index_sequence<_Idxs...>) const noexcept
{
return (((mapping().extents().extent(_Idxs) == index_type{0})) || ...);
}
[[nodiscard]] _CCCL_API constexpr bool empty() const noexcept
{
return __op_empty(make_index_sequence<rank()>());
}
_CCCL_API friend constexpr void swap(mdspan& __x, mdspan& __y) noexcept
{
swap(static_cast<__base&>(__x), static_cast<__base&>(__y));
}
[[nodiscard]] _CCCL_API constexpr const extents_type& extents() const noexcept
{
return mapping().extents();
}
[[nodiscard]] _CCCL_API constexpr const data_handle_type& data_handle() const noexcept
{
return this->template __get<0>();
}
[[nodiscard]] _CCCL_API constexpr const mapping_type& mapping() const noexcept
{
return this->template __get<1>();
}
[[nodiscard]] _CCCL_API constexpr const accessor_type& accessor() const noexcept
{
return this->template __get<2>();
}
[[nodiscard]] _CCCL_API static constexpr bool is_always_unique() noexcept(noexcept(mapping_type::is_always_unique()))
{
return mapping_type::is_always_unique();
}
[[nodiscard]] _CCCL_API static constexpr bool
is_always_exhaustive() noexcept(noexcept(mapping_type::is_always_exhaustive()))
{
return mapping_type::is_always_exhaustive();
}
[[nodiscard]] _CCCL_API static constexpr bool is_always_strided() noexcept(noexcept(mapping_type::is_always_strided()))
{
return mapping_type::is_always_strided();
}
[[nodiscard]]
_CCCL_API constexpr bool is_unique() const noexcept(noexcept(::cuda::std::declval<const mapping_type&>().is_unique()))
{
const auto& __tmp = mapping(); // workaround for clang with nodiscard
return __tmp.is_unique();
}
[[nodiscard]] _CCCL_API constexpr bool is_exhaustive() const
noexcept(noexcept(::cuda::std::declval<const mapping_type&>().is_exhaustive()))
{
const auto& __tmp = mapping(); // workaround for clang with nodiscard
return __tmp.is_exhaustive();
}
[[nodiscard]] _CCCL_API constexpr bool is_strided() const
noexcept(noexcept(::cuda::std::declval<const mapping_type&>().is_strided()))
{
const auto& __tmp = mapping(); // workaround for clang with nodiscard
return __tmp.is_strided();
}
[[nodiscard]] _CCCL_API constexpr index_type stride(rank_type __r) const
{
const auto& __tmp = mapping(); // workaround for clang with nodiscard
return static_cast<index_type>(__tmp.stride(__r));
}
};
_CCCL_TEMPLATE(class _ElementType, class... _OtherIndexTypes)
_CCCL_REQUIRES((sizeof...(_OtherIndexTypes) > 0) _CCCL_AND(is_convertible_v<_OtherIndexTypes, size_t>&&... && true))
_CCCL_DEDUCTION_GUIDE_ATTRIBUTES explicit mdspan(_ElementType*, _OtherIndexTypes...)
-> mdspan<_ElementType, extents<size_t, __maybe_static_ext<_OtherIndexTypes>...>>;
_CCCL_TEMPLATE(class _Pointer)
_CCCL_REQUIRES(is_pointer_v<remove_reference_t<_Pointer>>)
_CCCL_DEDUCTION_GUIDE_ATTRIBUTES mdspan(_Pointer&&)
-> mdspan<remove_pointer_t<remove_reference_t<_Pointer>>, extents<size_t>>;
_CCCL_TEMPLATE(class _CArray)
_CCCL_REQUIRES(is_array_v<_CArray> _CCCL_AND(rank_v<_CArray> == 1))
_CCCL_DEDUCTION_GUIDE_ATTRIBUTES mdspan(_CArray&)
-> mdspan<remove_all_extents_t<_CArray>, extents<size_t, extent_v<_CArray, 0>>>;
template <class _ElementType, class _OtherIndexType, size_t _Size>
_CCCL_DEDUCTION_GUIDE_ATTRIBUTES mdspan(_ElementType*, const array<_OtherIndexType, _Size>&)
-> mdspan<_ElementType, dextents<size_t, _Size>>;
template <class _ElementType, class _OtherIndexType, size_t _Size>
_CCCL_DEDUCTION_GUIDE_ATTRIBUTES mdspan(_ElementType*, span<_OtherIndexType, _Size>)
-> mdspan<_ElementType, dextents<size_t, _Size>>;
// This one is necessary because all the constructors take `data_handle_type`s, not
// `_ElementType*`s, and `data_handle_type` is taken from `accessor_type::data_handle_type`, which
// seems to throw off automatic deduction guides.
template <class _ElementType, class _OtherIndexType, size_t... _ExtentsPack>
_CCCL_DEDUCTION_GUIDE_ATTRIBUTES mdspan(_ElementType*, const extents<_OtherIndexType, _ExtentsPack...>&)
-> mdspan<_ElementType, extents<_OtherIndexType, _ExtentsPack...>>;
template <class _ElementType, class _MappingType>
_CCCL_DEDUCTION_GUIDE_ATTRIBUTES mdspan(_ElementType*, const _MappingType&)
-> mdspan<_ElementType, typename _MappingType::extents_type, typename _MappingType::layout_type>;
template <class _MappingType, class _AccessorType>
_CCCL_DEDUCTION_GUIDE_ATTRIBUTES
mdspan(const typename _AccessorType::data_handle_type, const _MappingType&, const _AccessorType&)
-> mdspan<typename _AccessorType::element_type,
typename _MappingType::extents_type,
typename _MappingType::layout_type,
_AccessorType>;
_CCCL_END_NAMESPACE_CUDA_STD
#include <cuda/std/__cccl/epilogue.h>
#endif // _CUDA_STD___MDSPAN_MDSPAN_H

View File

@@ -0,0 +1,190 @@
//===----------------------------------------------------------------------===//
//
// Part of libcu++, the C++ Standard Library for your entire system,
// 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
// SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES.
//
//===----------------------------------------------------------------------===//
#ifndef _CUDA_STD___MDSPAN_SUBMDSPAN_EXTENTS_H
#define _CUDA_STD___MDSPAN_SUBMDSPAN_EXTENTS_H
#include <cuda/std/detail/__config>
#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 <cuda/std/__concepts/concept_macros.h>
#include <cuda/std/__concepts/convertible_to.h>
#include <cuda/std/__fwd/mdspan.h>
#include <cuda/std/__mdspan/concepts.h>
#include <cuda/std/__mdspan/extents.h>
#include <cuda/std/__mdspan/submdspan_helper.h>
#include <cuda/std/__tuple_dir/tuple_like.h>
#include <cuda/std/__tuple_dir/tuple_size.h>
#include <cuda/std/__type_traits/is_integral.h>
#include <cuda/std/__type_traits/is_same.h>
#include <cuda/std/__type_traits/is_signed.h>
#include <cuda/std/__type_traits/is_unsigned.h>
#include <cuda/std/__type_traits/remove_cv.h>
#include <cuda/std/__utility/integer_sequence.h>
#include <cuda/std/array>
#include <cuda/std/tuple>
#include <cuda/std/__cccl/prologue.h>
_CCCL_BEGIN_NAMESPACE_CUDA_STD
// Helper to get an index_sequence of all slices that are not convertible to index_type
template <class _IndexType, class... _Slices, size_t... _FilteredIndices>
[[nodiscard]] _CCCL_API constexpr auto
__filter_slices_convertible_to_index(index_sequence<_FilteredIndices...>, index_sequence<>) noexcept
{
return index_sequence<_FilteredIndices...>{};
}
template <class _IndexType, class... _Slices, size_t... _SliceIndices, size_t _CurrentIndex, size_t... _Remaining>
[[nodiscard]] _CCCL_API constexpr auto __filter_slices_convertible_to_index(
index_sequence<_SliceIndices...>, index_sequence<_CurrentIndex, _Remaining...>) noexcept
{
using _SliceType = __get_slice_type<_CurrentIndex, _Slices...>;
if constexpr (convertible_to<_SliceType, _IndexType>)
{
return ::cuda::std::__filter_slices_convertible_to_index<_IndexType, _Slices...>(
index_sequence<_SliceIndices...>{}, index_sequence<_Remaining...>{});
}
else
{
return ::cuda::std::__filter_slices_convertible_to_index<_IndexType, _Slices...>(
index_sequence<_SliceIndices..., _CurrentIndex>{}, index_sequence<_Remaining...>{});
}
}
// [mdspan.sub.extents]
// [mdspan.sub.extents-4.2.2]
template <class _Extents, class _SliceType>
_CCCL_CONCEPT __subextents_is_index_pair = _CCCL_REQUIRES_EXPR((_Extents, _SliceType))(
requires(__index_pair_like<_SliceType, typename _Extents::index_type>),
requires(__integral_constant_like<tuple_element_t<0, _SliceType>>),
requires(__integral_constant_like<tuple_element_t<1, _SliceType>>));
// [mdspan.sub.extents-4.2.3]
template <class _Extents, class _SliceType>
_CCCL_CONCEPT __subextents_is_strided_slice_zero_extent = _CCCL_REQUIRES_EXPR((_Extents, _SliceType))(
requires(__is_strided_slice<remove_cv_t<_SliceType>>),
requires(__integral_constant_like<typename _SliceType::extent_type>),
requires(typename _SliceType::extent_type() == 0));
// [mdspan.sub.extents-4.2.4]
template <class _SliceType>
_CCCL_CONCEPT __subextents_is_strided_slice = _CCCL_REQUIRES_EXPR((_SliceType))(
requires(__is_strided_slice<remove_cv_t<_SliceType>>),
requires(__integral_constant_like<typename _SliceType::extent_type>),
requires(__integral_constant_like<typename _SliceType::stride_type>));
struct __get_subextent
{
template <class _Extents, size_t _SliceIndex, class _SliceType>
[[nodiscard]] _CCCL_API static constexpr size_t __get_static_subextents() noexcept
{
// [mdspan.sub.extents-4.2.1]
if constexpr (convertible_to<_SliceType, full_extent_t>)
{
return _Extents::static_extent(_SliceIndex);
}
// [mdspan.sub.extents-4.2.2]
else if constexpr (__subextents_is_index_pair<_Extents, _SliceType>)
{
return ::cuda::std::__de_ice(tuple_element_t<1, _SliceType>())
- ::cuda::std::__de_ice(tuple_element_t<0, _SliceType>());
}
// [mdspan.sub.extents-4.2.3]
else if constexpr (__subextents_is_strided_slice_zero_extent<_Extents, _SliceType>)
{
return 0;
}
// [mdspan.sub.extents-4.2.4]
else if constexpr (__subextents_is_strided_slice<_SliceType>)
{
return 1
+ (::cuda::std::__de_ice(typename _SliceType::extent_type()) - 1)
/ ::cuda::std::__de_ice(typename _SliceType::stride_type());
}
else
{
// [mdspan.sub.extents-4.2.5]
return dynamic_extent;
}
}
template <size_t _SliceIndex, class _Extents, class... _Slices>
[[nodiscard]] _CCCL_API static constexpr typename _Extents::index_type
__get_dynamic_subextents(const _Extents& __src, _Slices... __slices) noexcept
{
using _SliceType = __get_slice_type<_SliceIndex, _Slices...>;
// [mdspan.sub.extents-5.1]
if constexpr (__is_strided_slice<remove_cv_t<_SliceType>>)
{
_SliceType& __slice = ::cuda::std::__get_slice_at<_SliceIndex>(__slices...);
return __slice.extent == 0
? 0
: 1 + (::cuda::std::__de_ice(__slice.extent) - 1) / ::cuda::std::__de_ice(__slice.stride);
}
// [mdspan.sub.extents-5.2]
else
{
return ::cuda::std::__last_extent_from_slice<_SliceIndex>(__src, __slices...)
- ::cuda::std::__first_extent_from_slice<typename _Extents::index_type, _SliceIndex>(__slices...);
}
}
template <class _Extents, class... _Slices, size_t... _SliceIndices>
[[nodiscard]] _CCCL_API constexpr auto
__impl(index_sequence<_SliceIndices...>, const _Extents& __src, _Slices... __slices) noexcept
{
using _IndexType = typename _Extents::index_type;
using _SubExtents =
extents<_IndexType,
__get_static_subextents<_Extents, _SliceIndices, __get_slice_type<_SliceIndices, _Slices...>>()...>;
return _SubExtents{__get_dynamic_subextents<_SliceIndices>(__src, __slices...)...};
}
template <class _Extents, class... _Slices>
[[nodiscard]] _CCCL_API constexpr auto operator()(const _Extents& __src, _Slices... __slices) noexcept
{
const auto __filtered_indices = __filter_slices_convertible_to_index<typename _Extents::index_type, _Slices...>(
index_sequence<>{}, ::cuda::std::index_sequence_for<_Slices...>());
return __impl(__filtered_indices, __src, __slices...);
}
};
template <class _IndexType, class _SliceType>
inline constexpr bool __is_valid_subextents =
convertible_to<_SliceType, _IndexType> || __index_pair_like<_SliceType, _IndexType>
|| is_convertible_v<_SliceType, full_extent_t> || __is_strided_slice<remove_cv_t<_SliceType>>;
_CCCL_TEMPLATE(class _Extents, class... _Slices)
_CCCL_REQUIRES((_Extents::rank() == sizeof...(_Slices)))
[[nodiscard]] _CCCL_API constexpr auto submdspan_extents(const _Extents& __src, _Slices... __slices)
{
static_assert(((__is_valid_subextents<typename _Extents::index_type, _Slices>) && ... && true),
"[mdspan.sub.extents] For each rank index k of src.extents(), exactly one of the following is true:");
return __get_subextent{}(__src, __slices...);
}
template <class _Extents, class... _Slices>
using __get_subextents_t =
decltype(::cuda::std::submdspan_extents(::cuda::std::declval<_Extents>(), ::cuda::std::declval<_Slices>()...));
_CCCL_END_NAMESPACE_CUDA_STD
#include <cuda/std/__cccl/epilogue.h>
#endif // _CUDA_STD___MDSPAN_SUBMDSPAN_EXTENTS_H

View File

@@ -0,0 +1,202 @@
//===----------------------------------------------------------------------===//
//
// Part of libcu++, the C++ Standard Library for your entire system,
// 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
// SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES.
//
//===----------------------------------------------------------------------===//
#ifndef _CUDA_STD___MDSPAN_SUBMDSPAN_HELPER_H
#define _CUDA_STD___MDSPAN_SUBMDSPAN_HELPER_H
#include <cuda/std/detail/__config>
#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 <cuda/std/__concepts/concept_macros.h>
#include <cuda/std/__concepts/convertible_to.h>
#include <cuda/std/__fwd/mdspan.h>
#include <cuda/std/__mdspan/concepts.h>
#include <cuda/std/__mdspan/extents.h>
#include <cuda/std/__type_traits/is_integral.h>
#include <cuda/std/__type_traits/is_same.h>
#include <cuda/std/__type_traits/is_signed.h>
#include <cuda/std/__type_traits/is_unsigned.h>
#include <cuda/std/__type_traits/type_list.h>
#include <cuda/std/__utility/integer_sequence.h>
#include <cuda/std/array>
#include <cuda/std/tuple>
#include <cuda/std/__cccl/prologue.h>
_CCCL_BEGIN_NAMESPACE_CUDA_STD
// [mdspan.sub.overview]-2.5
template <class _IndexType, class... _SliceTypes>
[[nodiscard]] _CCCL_API constexpr array<size_t, sizeof...(_SliceTypes)> __map_rank(size_t __count = 0) noexcept
{
return {(convertible_to<_SliceTypes, _IndexType> ? dynamic_extent : __count++)...};
}
// [mdspan.submdspan.strided.slice]
template <class _OffsetType, class _ExtentType, class _StrideType>
struct strided_slice
{
using offset_type = _OffsetType;
using extent_type = _ExtentType;
using stride_type = _StrideType;
static_assert(__index_like<offset_type>,
"[mdspan.submdspan.strided.slice] cuda::std::strided_slice::offset_type must be signed or unsigned or "
"integral-constant-like");
static_assert(__index_like<extent_type>,
"[mdspan.submdspan.strided.slice] cuda::std::strided_slice::extent_type must be signed or unsigned or "
"integral-constant-like");
static_assert(__index_like<stride_type>,
"[mdspan.submdspan.strided.slice] cuda::std::strided_slice::stride_type must be signed or unsigned or "
"integral-constant-like");
_CCCL_NO_UNIQUE_ADDRESS offset_type offset{};
_CCCL_NO_UNIQUE_ADDRESS extent_type extent{};
_CCCL_NO_UNIQUE_ADDRESS stride_type stride{};
};
template <class _OffsetType, class _ExtentType, class _StrideType>
_CCCL_DEDUCTION_GUIDE_ATTRIBUTES strided_slice(_OffsetType, _ExtentType, _StrideType)
-> strided_slice<_OffsetType, _ExtentType, _StrideType>;
template <typename>
inline constexpr bool __is_strided_slice = false;
template <class _OffsetType, class _ExtentType, class _StrideType>
inline constexpr bool __is_strided_slice<strided_slice<_OffsetType, _ExtentType, _StrideType>> = true;
struct full_extent_t
{
_CCCL_HIDE_FROM_ABI explicit full_extent_t() = default;
};
inline constexpr full_extent_t full_extent{};
// [mdspan.submdspan.helpers]
_CCCL_TEMPLATE(class _Tp)
_CCCL_REQUIRES((!__integral_constant_like<_Tp>) )
[[nodiscard]] _CCCL_API constexpr _Tp __de_ice(_Tp __val) noexcept
{
return __val;
}
_CCCL_TEMPLATE(class _Tp)
_CCCL_REQUIRES(__integral_constant_like<_Tp>)
[[nodiscard]] _CCCL_API constexpr auto __de_ice(_Tp) noexcept
{
return _Tp::value;
}
template <class _IndexType, class _From>
[[nodiscard]] _CCCL_API constexpr auto __index_cast(_From&& __from) noexcept
{
if constexpr (is_integral_v<_From> && !is_same_v<_From, bool>)
{
return __from;
}
else
{
return static_cast<_IndexType>(__from);
}
}
_CCCL_EXEC_CHECK_DISABLE
template <size_t _Index, class... _Slices>
[[nodiscard]] _CCCL_API constexpr decltype(auto) __get_slice_at(_Slices&&... __slices) noexcept
{
// Pull in `::std::get` via ADL for host library types
using ::cuda::std::get;
#if _CCCL_COMPILER(MSVC)
tuple<_Slices...> __tuple{::cuda::std::forward<_Slices>(__slices)...};
return get<_Index>(::cuda::std::move(__tuple));
#else // ^^^ _CCCL_COMPILER(MSVC) ^^^ / vvv !_CCCL_COMPILER(MSVC) vvv
return get<_Index>(::cuda::std::forward_as_tuple(::cuda::std::forward<_Slices>(__slices)...));
#endif // !_CCCL_COMPILER(MSVC)
}
template <size_t _Index, class... _Slices>
using __get_slice_type = __type_at_c<_Index, __type_list<_Slices...>>;
_CCCL_EXEC_CHECK_DISABLE
template <class _IndexType, size_t _Index, class... _Slices>
[[nodiscard]] _CCCL_API constexpr _IndexType __first_extent_from_slice(_Slices... __slices) noexcept
{
static_assert(is_signed_v<_IndexType> || is_unsigned_v<_IndexType>,
"[mdspan.sub.helpers] mandates IndexType to be a signed or unsigned integral");
using _SliceType = __get_slice_type<_Index, _Slices...>;
[[maybe_unused]] _SliceType& __slice = ::cuda::std::__get_slice_at<_Index>(__slices...);
if constexpr (convertible_to<_SliceType, _IndexType>)
{
return ::cuda::std::__index_cast<_IndexType>(__slice);
}
else
{
if constexpr (__index_pair_like<_SliceType, _IndexType>)
{
// Pull in `::std::get` via ADL for host library types
using ::cuda::std::get;
return ::cuda::std::__index_cast<_IndexType>(get<0>(__slice));
}
else if constexpr (__is_strided_slice<_SliceType>)
{
return ::cuda::std::__index_cast<_IndexType>(::cuda::std::__de_ice(__slice.offset));
}
else
{
return 0;
}
}
}
_CCCL_EXEC_CHECK_DISABLE
template <size_t _Index, class _Extents, class... _Slices>
[[nodiscard]] _CCCL_API constexpr typename _Extents::index_type
__last_extent_from_slice(const _Extents& __src, _Slices... __slices) noexcept
{
static_assert(__is_cuda_std_extents_v<_Extents>,
"[mdspan.sub.helpers] mandates Extents to be a specialization of extents");
using _IndexType = typename _Extents::index_type;
using _SliceType = __get_slice_type<_Index, _Slices...>;
[[maybe_unused]] _SliceType& __slice = ::cuda::std::__get_slice_at<_Index>(__slices...);
if constexpr (convertible_to<_SliceType, _IndexType>)
{
return ::cuda::std::__index_cast<_IndexType>(::cuda::std::__de_ice(__slice) + 1);
}
else
{
if constexpr (__index_pair_like<_SliceType, _IndexType>)
{
// Pull in `::std::get` via ADL for host library types
using ::cuda::std::get;
return ::cuda::std::__index_cast<_IndexType>(get<1>(__slice));
}
else if constexpr (__is_strided_slice<_SliceType>)
{
return ::cuda::std::__index_cast<_IndexType>(
::cuda::std::__de_ice(__slice.offset) * ::cuda::std::__de_ice(__slice.extent));
}
else
{
return ::cuda::std::__index_cast<_IndexType>(__src.extent(_Index));
}
}
}
_CCCL_END_NAMESPACE_CUDA_STD
#include <cuda/std/__cccl/epilogue.h>
#endif // _CUDA_STD___MDSPAN_SUBMDSPAN_HELPER_H

View File

@@ -0,0 +1,341 @@
//===----------------------------------------------------------------------===//
//
// Part of libcu++, the C++ Standard Library for your entire system,
// 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
// SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES.
//
//===----------------------------------------------------------------------===//
#ifndef _CUDA_STD___MDSPAN_SUBMDSPAN_MAPPING_H
#define _CUDA_STD___MDSPAN_SUBMDSPAN_MAPPING_H
#include <cuda/std/detail/__config>
#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 <cuda/std/__fwd/mdspan.h>
#include <cuda/std/__mdspan/concepts.h>
#include <cuda/std/__mdspan/extents.h>
#include <cuda/std/__mdspan/layout_left.h>
#include <cuda/std/__mdspan/layout_right.h>
#include <cuda/std/__mdspan/layout_stride.h>
#include <cuda/std/__mdspan/mdspan.h>
#include <cuda/std/__mdspan/submdspan_extents.h>
#include <cuda/std/__mdspan/submdspan_helper.h>
#include <cuda/std/__type_traits/make_unsigned.h>
#include <cuda/std/__type_traits/remove_const.h>
#include <cuda/std/__type_traits/type_list.h>
#include <cuda/std/__utility/integer_sequence.h>
#include <cuda/std/array>
#include <cuda/std/__cccl/prologue.h>
_CCCL_BEGIN_NAMESPACE_CUDA_STD
// [mdspan.sub.map]
// [mdspan.submdspan.submdspan.mapping.result]
template <class _LayoutMapping>
struct submdspan_mapping_result
{
static_assert(__mdspan_detail::__layout_mapping_req<_LayoutMapping>,
"[mdspan.submdspan.submdspan.mapping.result] shall meet the layout mapping requirements");
_CCCL_NO_UNIQUE_ADDRESS _LayoutMapping mapping{};
size_t offset{};
};
// [mdspan.sub.map.common]
// mdspan.sub.map.common-2
template <class _Extents, class... _Slices>
_CCCL_CONCEPT __matching_number_of_slices = sizeof...(_Slices) == _Extents::rank();
template <size_t _SliceIndex, class _LayoutMapping, class... _Slices>
[[nodiscard]] _CCCL_API constexpr auto
__get_submdspan_strides(const _LayoutMapping& __mapping, _Slices... __slices) noexcept
{
using _SliceType = __get_slice_type<_SliceIndex, _Slices...>;
using _Extents = typename _LayoutMapping::extents_type;
using _IndexType = typename _Extents::index_type;
if constexpr (__is_strided_slice<remove_cv_t<_SliceType>>)
{
_SliceType& __slice = ::cuda::std::__get_slice_at<_SliceIndex>(__slices...);
using __unsigned_stride = make_unsigned_t<typename _SliceType::stride_type>;
using __unsigned_extent = make_unsigned_t<typename _SliceType::extent_type>;
return static_cast<_IndexType>(
__mapping.stride(_SliceIndex)
* (static_cast<__unsigned_stride>(__slice.stride) < static_cast<__unsigned_extent>(__slice.extent)
? ::cuda::std::__de_ice(__slice.stride)
: 1));
}
else
{
return static_cast<_IndexType>(__mapping.stride(_SliceIndex));
}
}
template <class _LayoutMapping, class... _Slices, size_t... _SliceIndices>
[[nodiscard]] _CCCL_API constexpr auto
__submdspan_strides(index_sequence<_SliceIndices...>, const _LayoutMapping& __mapping, _Slices... __slices) noexcept
{
using _Extents = typename _LayoutMapping::extents_type;
using _IndexType = typename _Extents::index_type;
using _SubExtents = __get_subextents_t<_Extents, _Slices...>;
return array<_IndexType, _SubExtents::rank()>{
::cuda::std::__get_submdspan_strides<_SliceIndices>(__mapping, __slices...)...};
}
_CCCL_TEMPLATE(class _LayoutMapping, class... _Slices)
_CCCL_REQUIRES(__matching_number_of_slices<typename _LayoutMapping::extents_type, _Slices...>)
[[nodiscard]] _CCCL_API constexpr auto __submdspan_strides(const _LayoutMapping& __mapping, _Slices... __slices)
{
using _Extents = typename _LayoutMapping::extents_type;
using _IndexType = typename _Extents::index_type;
const auto __filtered_indices = __filter_slices_convertible_to_index<_IndexType, _Slices...>(
index_sequence<>{}, ::cuda::std::index_sequence_for<_Slices...>());
return ::cuda::std::__submdspan_strides(__filtered_indices, __mapping, __slices...);
}
// [mdspan.sub.map.common-8]
template <class _LayoutMapping, class... _Slices, size_t... _SliceIndices>
[[nodiscard]] _CCCL_API constexpr size_t
__submdspan_offset(index_sequence<_SliceIndices...>, const _LayoutMapping& __mapping, _Slices... __slices)
{
using _Extents = typename _LayoutMapping::extents_type;
using _IndexType = typename _Extents::index_type;
// If first_<index_type, k>(slices...)
const array<_IndexType, _Extents::rank()> __offsets = {
::cuda::std::__first_extent_from_slice<_IndexType, _SliceIndices>(__slices...)...};
using _SubExtents = __get_subextents_t<_Extents, _Slices...>;
for (size_t __index = 0; __index != _SubExtents::rank(); ++__index)
{
// If first_<index_type, k>(slices...) equals extents().extent(k) for any rank index k of extents()
if (__offsets[__index] == __mapping.extents().extent(__index))
{
// then let offset be a value of type size_t equal to (*this).required_span_size()
return static_cast<size_t>(__mapping.required_span_size());
}
}
// Otherwise, let offset be a value of type size_t equal to (*this)(first_<index_type, P>(slices...)...).
return static_cast<size_t>(__mapping(__offsets[_SliceIndices]...));
}
_CCCL_TEMPLATE(class _LayoutMapping, class... _Slices)
_CCCL_REQUIRES(__matching_number_of_slices<typename _LayoutMapping::extents_type, _Slices...>)
[[nodiscard]] _CCCL_API constexpr size_t __submdspan_offset(const _LayoutMapping& __mapping, _Slices... __slices)
{
return ::cuda::std::__submdspan_offset(::cuda::std::index_sequence_for<_Slices...>(), __mapping, __slices...);
}
// [mdspan.sub.map.common-9]
// [mdspan.sub.map.common-9.1]
template <class _SliceType>
_CCCL_CONCEPT __is_strided_slice_stride_of_one = _CCCL_REQUIRES_EXPR((_SliceType))(
requires(__is_strided_slice<remove_cv_t<_SliceType>>),
requires(__integral_constant_like<typename _SliceType::stride_type>),
requires(_SliceType::stride_type::value == 1));
template <class _LayoutMapping, class _SliceType>
_CCCL_API constexpr bool __is_unit_stride_slice()
{
// [mdspan.sub.map.common-9.1]
// NOLINTBEGIN(bugprone-branch-clone)
if constexpr (__is_strided_slice_stride_of_one<_SliceType>)
{
return true;
}
// [mdspan.sub.map.common-9.2]
else if constexpr (__index_pair_like<_SliceType, typename _LayoutMapping::index_type>)
{
return true;
}
// [mdspan.sub.map.common-9.3]
else if constexpr (is_convertible_v<_SliceType, full_extent_t>)
{
return true;
}
else
{
return false;
}
// NOLINTEND(bugprone-branch-clone)
}
// [mdspan.sub.map.left]
template <class _LayoutMapping, class _SubExtents, class _Slice, class... _OtherSlices>
_CCCL_API constexpr bool __can_layout_left()
{
// [mdspan.sub.map.left-1.2]
if constexpr (_SubExtents::rank() == 0)
{
return true;
}
// [mdspan.sub.map.left-1.3.2]
else if constexpr (sizeof...(_OtherSlices) == 0)
{
return ::cuda::std::__is_unit_stride_slice<_LayoutMapping, _Slice>();
}
// [mdspan.sub.map.left-1.3.1]
else if constexpr (is_convertible_v<_Slice, full_extent_t>)
{
return ::cuda::std::__can_layout_left<_LayoutMapping, _SubExtents, _OtherSlices...>();
}
else
{
return false;
}
}
_CCCL_TEMPLATE(class _Extents, class... _Slices)
_CCCL_REQUIRES(__matching_number_of_slices<_Extents, _Slices...>)
[[nodiscard]] _CCCL_API constexpr auto
__submdspan_mapping_impl(const typename layout_left::mapping<_Extents>& __mapping, _Slices... __slices)
{
// [mdspan.sub.map.left-1.1]
if constexpr (_Extents::rank() == 0)
{
return submdspan_mapping_result{__mapping, 0};
}
else
{
// [mdspan.sub.map.left-1.2]
// [mdspan.sub.map.left-1.3]
using _SubExtents = __get_subextents_t<_Extents, _Slices...>;
const auto __sub_ext = ::cuda::std::submdspan_extents(__mapping.extents(), __slices...);
const auto __offset = ::cuda::std::__submdspan_offset(__mapping, __slices...);
if constexpr (::cuda::std::__can_layout_left<typename layout_left::mapping<_Extents>, _SubExtents, _Slices...>())
{
using __sub_mapping_t = layout_left::template mapping<_SubExtents>;
return submdspan_mapping_result<__sub_mapping_t>{__sub_mapping_t{__sub_ext}, __offset};
}
// [mdspan.sub.map.left-1.4]
// TODO: Implement padded layouts
else
{
// [mdspan.sub.map.left-1.5]
using __sub_mapping_t = layout_stride::template mapping<_SubExtents>;
const auto __sub_strides = ::cuda::std::__submdspan_strides(__mapping, __slices...);
return submdspan_mapping_result<__sub_mapping_t>{__sub_mapping_t{__sub_ext, __sub_strides}, __offset};
}
}
}
template <class _LayoutMapping, class _SubExtents, class _Slice, class... _OtherSlices>
_CCCL_API constexpr bool __can_layout_right()
{
// [mdspan.sub.map.right-1.2]
if constexpr (_SubExtents::rank() == 0)
{
return true;
}
// [mdspan.sub.map.right-1.3.2]
else if constexpr (sizeof...(_OtherSlices) == 0)
{
return ::cuda::std::__is_unit_stride_slice<_LayoutMapping, _Slice>();
}
// [mdspan.sub.map.right-1.3.1]
else if constexpr (is_convertible_v<_Slice, full_extent_t>)
{
return ::cuda::std::__can_layout_left<_LayoutMapping, _SubExtents, _OtherSlices...>();
}
else
{
return false;
}
}
_CCCL_TEMPLATE(class _Extents, class... _Slices)
_CCCL_REQUIRES(__matching_number_of_slices<_Extents, _Slices...>)
[[nodiscard]] _CCCL_API constexpr auto
__submdspan_mapping_impl(const typename layout_right::mapping<_Extents>& __mapping, _Slices... __slices)
{
// [mdspan.sub.map.right-1.1]
if constexpr (_Extents::rank() == 0)
{
return submdspan_mapping_result{__mapping, 0};
}
else
{
// [mdspan.sub.map.right-1.2]
// [mdspan.sub.map.right-1.3]
using _SubExtents = __get_subextents_t<_Extents, _Slices...>;
const auto __sub_ext = ::cuda::std::submdspan_extents(__mapping.extents(), __slices...);
const auto __offset = ::cuda::std::__submdspan_offset(__mapping, __slices...);
if constexpr (::cuda::std::__can_layout_right<typename layout_left::mapping<_Extents>, _SubExtents, _Slices...>())
{
using __sub_mapping_t = layout_right::template mapping<_SubExtents>;
return submdspan_mapping_result<__sub_mapping_t>{__sub_mapping_t{__sub_ext}, __offset};
}
// [mdspan.sub.map.right-1.4]
// TODO: Implement padded layouts
else
{
// [mdspan.sub.map.right-1.5]
using __sub_mapping_t = layout_stride::template mapping<_SubExtents>;
const auto __sub_strides = ::cuda::std::__submdspan_strides(__mapping, __slices...);
return submdspan_mapping_result<__sub_mapping_t>{__sub_mapping_t{__sub_ext, __sub_strides}, __offset};
}
}
}
_CCCL_TEMPLATE(class _Extents, class... _Slices)
_CCCL_REQUIRES(__matching_number_of_slices<_Extents, _Slices...>)
[[nodiscard]] _CCCL_API constexpr auto
__submdspan_mapping_impl(const typename layout_stride::mapping<_Extents>& __mapping, _Slices... __slices)
{
// [mdspan.sub.map.stride-1.1]
if constexpr (_Extents::rank() == 0)
{
return submdspan_mapping_result{__mapping, 0};
}
else
{
// [mdspan.sub.map.stride-1.2]
using _SubExtents = __get_subextents_t<_Extents, _Slices...>;
using __sub_mapping_t = layout_stride::template mapping<_SubExtents>;
const auto __sub_ext = ::cuda::std::submdspan_extents(__mapping.extents(), __slices...);
const auto __offset = ::cuda::std::__submdspan_offset(__mapping, __slices...);
const auto __sub_strides = ::cuda::std::__submdspan_strides(__mapping, __slices...);
return submdspan_mapping_result<__sub_mapping_t>{__sub_mapping_t{__sub_ext, __sub_strides}, __offset};
}
}
_CCCL_TEMPLATE(class _LayoutMapping, class... _Slices)
_CCCL_REQUIRES(__matching_number_of_slices<typename _LayoutMapping::extents_type, _Slices...>)
[[nodiscard]] _CCCL_API constexpr auto submdspan_mapping(const _LayoutMapping& __mapping, _Slices... __slices)
{
return ::cuda::std::__submdspan_mapping_impl(__mapping, __slices...);
}
// [mdspan.sub.sub]
template <class _LayoutMapping, class... _Slices>
_CCCL_CONCEPT __can_submdspan_mapping =
_CCCL_REQUIRES_EXPR((_LayoutMapping, variadic _Slices), const _LayoutMapping& __mapping, _Slices... __slices)(
(::cuda::std::submdspan_mapping(__mapping, __slices...)));
_CCCL_TEMPLATE(class _Tp, class _Extents, class _Layout, class _Accessor, class... _Slices)
_CCCL_REQUIRES(__matching_number_of_slices<_Extents, _Slices...> _CCCL_AND
__can_submdspan_mapping<typename _Layout::template mapping<_Extents>, _Slices...>)
[[nodiscard]] _CCCL_API constexpr auto
submdspan(const mdspan<_Tp, _Extents, _Layout, _Accessor>& __src, _Slices... __slices)
{
auto __sub_map_result = ::cuda::std::submdspan_mapping(__src.mapping(), __slices...);
return mdspan(__src.accessor().offset(__src.data_handle(), __sub_map_result.offset),
__sub_map_result.mapping,
typename _Accessor::offset_policy(__src.accessor()));
}
_CCCL_END_NAMESPACE_CUDA_STD
#include <cuda/std/__cccl/epilogue.h>
#endif // _CUDA_STD___MDSPAN_SUBMDSPAN_MAPPING_H