[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:
@@ -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
|
||||
141
cccl_upstream/libcudacxx/include/cuda/std/__mdspan/concepts.h
Normal file
141
cccl_upstream/libcudacxx/include/cuda/std/__mdspan/concepts.h
Normal 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
|
||||
@@ -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
|
||||
368
cccl_upstream/libcudacxx/include/cuda/std/__mdspan/empty_base.h
Normal file
368
cccl_upstream/libcudacxx/include/cuda/std/__mdspan/empty_base.h
Normal 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
|
||||
727
cccl_upstream/libcudacxx/include/cuda/std/__mdspan/extents.h
Normal file
727
cccl_upstream/libcudacxx/include/cuda/std/__mdspan/extents.h
Normal 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
|
||||
295
cccl_upstream/libcudacxx/include/cuda/std/__mdspan/layout_left.h
Normal file
295
cccl_upstream/libcudacxx/include/cuda/std/__mdspan/layout_left.h
Normal 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
|
||||
@@ -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
|
||||
@@ -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
|
||||
593
cccl_upstream/libcudacxx/include/cuda/std/__mdspan/mdspan.h
Normal file
593
cccl_upstream/libcudacxx/include/cuda/std/__mdspan/mdspan.h
Normal 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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user