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
654 lines
24 KiB
Plaintext
654 lines
24 KiB
Plaintext
//===----------------------------------------------------------------------===//
|
|
//
|
|
// 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) 2023 NVIDIA CORPORATION & AFFILIATES.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef _CUDA_STD_SPAN
|
|
#define _CUDA_STD_SPAN
|
|
|
|
#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/equality_comparable.h>
|
|
#include <cuda/std/__exception/exception_macros.h>
|
|
#include <cuda/std/__fwd/array.h>
|
|
#include <cuda/std/__fwd/span.h>
|
|
#include <cuda/std/__fwd/string.h>
|
|
#include <cuda/std/__host_stdlib/stdexcept>
|
|
#include <cuda/std/__iterator/access.h>
|
|
#include <cuda/std/__iterator/concepts.h>
|
|
#include <cuda/std/__iterator/data.h>
|
|
#include <cuda/std/__iterator/distance.h>
|
|
#include <cuda/std/__iterator/empty.h>
|
|
#include <cuda/std/__iterator/reverse_access.h>
|
|
#include <cuda/std/__iterator/reverse_iterator.h>
|
|
#include <cuda/std/__iterator/size.h>
|
|
#include <cuda/std/__iterator/wrap_iter.h>
|
|
#include <cuda/std/__ranges/concepts.h>
|
|
#include <cuda/std/__ranges/data.h>
|
|
#include <cuda/std/__ranges/enable_borrowed_range.h>
|
|
#include <cuda/std/__ranges/enable_view.h>
|
|
#include <cuda/std/__ranges/size.h>
|
|
#include <cuda/std/__type_traits/integral_constant.h>
|
|
#include <cuda/std/__type_traits/integral_constant_like.h>
|
|
#include <cuda/std/__type_traits/is_array.h>
|
|
#include <cuda/std/__type_traits/is_const.h>
|
|
#include <cuda/std/__type_traits/is_convertible.h>
|
|
#include <cuda/std/__type_traits/is_integral.h>
|
|
#include <cuda/std/__type_traits/is_same.h>
|
|
#include <cuda/std/__type_traits/remove_const.h>
|
|
#include <cuda/std/__type_traits/remove_cv.h>
|
|
#include <cuda/std/__type_traits/remove_cvref.h>
|
|
#include <cuda/std/__type_traits/remove_reference.h>
|
|
#include <cuda/std/__type_traits/type_identity.h>
|
|
#include <cuda/std/array>
|
|
#include <cuda/std/cstddef>
|
|
#include <cuda/std/initializer_list>
|
|
#include <cuda/std/version>
|
|
|
|
#include <cuda/std/__cccl/prologue.h>
|
|
|
|
_CCCL_BEGIN_NAMESPACE_CUDA_STD
|
|
|
|
template <class _From, class _To>
|
|
_CCCL_CONCEPT __span_array_convertible = is_convertible_v<_From (*)[], _To (*)[]>;
|
|
|
|
template <class _Range, class _ElementType>
|
|
_CCCL_CONCEPT __span_compatible_range = _CCCL_REQUIRES_EXPR((_Range, _ElementType))(
|
|
requires(::cuda::std::ranges::contiguous_range<_Range>),
|
|
requires(::cuda::std::ranges::sized_range<_Range>),
|
|
requires((::cuda::std::ranges::borrowed_range<_Range> || is_const_v<_ElementType>) ),
|
|
requires((!is_array_v<remove_cvref_t<_Range>>) ),
|
|
requires((!__is_cuda_std_span_v<remove_cvref_t<_Range>> && !__is_cuda_std_array_v<remove_cvref_t<_Range>>) ),
|
|
requires(
|
|
is_convertible_v<remove_reference_t<::cuda::std::ranges::range_reference_t<_Range>> (*)[], _ElementType (*)[]>));
|
|
|
|
template <class _It, class _Tp>
|
|
_CCCL_CONCEPT __span_compatible_iterator = _CCCL_REQUIRES_EXPR((_It, _Tp)) //
|
|
(requires(contiguous_iterator<_It>),
|
|
requires(__span_array_convertible<remove_reference_t<iter_reference_t<_It>>, _Tp>));
|
|
|
|
template <class _Sentinel, class _It>
|
|
_CCCL_CONCEPT __span_compatible_sentinel_for = _CCCL_REQUIRES_EXPR((_Sentinel, _It)) //
|
|
(requires(sized_sentinel_for<_Sentinel, _It>), requires(!is_convertible_v<_Sentinel, size_t>));
|
|
|
|
template <class _Tp, bool = __integral_constant_like<_Tp>>
|
|
inline constexpr size_t __maybe_static_ext = dynamic_extent;
|
|
|
|
template <class _Tp>
|
|
inline constexpr size_t __maybe_static_ext<_Tp, true> = {_Tp::value};
|
|
|
|
template <typename _Tp, size_t _Extent>
|
|
class _CCCL_TYPE_VISIBILITY_DEFAULT span
|
|
{
|
|
public:
|
|
// constants and types
|
|
using element_type = _Tp;
|
|
using value_type = remove_cv_t<_Tp>;
|
|
using size_type = size_t;
|
|
using difference_type = ptrdiff_t;
|
|
using pointer = _Tp*;
|
|
using const_pointer = const _Tp*;
|
|
using reference = _Tp&;
|
|
using const_reference = const _Tp&;
|
|
using iterator = __wrap_iter<pointer>;
|
|
using reverse_iterator = ::cuda::std::reverse_iterator<iterator>;
|
|
|
|
static constexpr size_type extent = _Extent;
|
|
|
|
// [span.cons], span constructors, copy, assignment, and destructor
|
|
_CCCL_TEMPLATE(size_t _Sz = _Extent)
|
|
_CCCL_REQUIRES((_Sz == 0))
|
|
_CCCL_API constexpr span() noexcept
|
|
: __data_{nullptr}
|
|
{}
|
|
|
|
_CCCL_HIDE_FROM_ABI span(const span&) noexcept = default;
|
|
_CCCL_HIDE_FROM_ABI span& operator=(const span&) noexcept = default;
|
|
|
|
_CCCL_EXEC_CHECK_DISABLE
|
|
_CCCL_TEMPLATE(class _It)
|
|
_CCCL_REQUIRES(__span_compatible_iterator<_It, element_type>)
|
|
_CCCL_API constexpr explicit span(_It __first, [[maybe_unused]] size_type __count)
|
|
: __data_{::cuda::std::to_address(__first)}
|
|
{
|
|
_CCCL_ASSERT(_Extent == __count, "size mismatch in span's constructor (iterator, len)");
|
|
}
|
|
|
|
_CCCL_EXEC_CHECK_DISABLE
|
|
_CCCL_TEMPLATE(class _It, class _End)
|
|
_CCCL_REQUIRES(__span_compatible_iterator<_It, element_type> _CCCL_AND __span_compatible_sentinel_for<_End, _It>)
|
|
_CCCL_API constexpr explicit span(_It __first, [[maybe_unused]] _End __last)
|
|
: __data_{::cuda::std::to_address(__first)}
|
|
{
|
|
_CCCL_ASSERT((__last - __first >= 0), "invalid range in span's constructor (iterator, sentinel)");
|
|
_CCCL_ASSERT(__last - __first == _Extent,
|
|
"invalid range in span's constructor (iterator, sentinel): last - first != extent");
|
|
}
|
|
|
|
_CCCL_TEMPLATE(size_t _Sz = _Extent)
|
|
_CCCL_REQUIRES((_Sz != 0))
|
|
_CCCL_API constexpr span(type_identity_t<element_type> (&__arr)[_Sz]) noexcept
|
|
: __data_{__arr}
|
|
{}
|
|
|
|
_CCCL_TEMPLATE(class _OtherElementType)
|
|
_CCCL_REQUIRES(__span_array_convertible<_OtherElementType, element_type>)
|
|
_CCCL_API constexpr span(array<_OtherElementType, _Extent>& __arr) noexcept
|
|
: __data_{__arr.data()}
|
|
{}
|
|
|
|
_CCCL_TEMPLATE(class _OtherElementType)
|
|
_CCCL_REQUIRES(__span_array_convertible<const _OtherElementType, element_type>)
|
|
_CCCL_API constexpr span(const array<_OtherElementType, _Extent>& __arr) noexcept
|
|
: __data_{__arr.data()}
|
|
{}
|
|
|
|
#if _CCCL_HAS_HOST_STD_LIB()
|
|
_CCCL_EXEC_CHECK_DISABLE
|
|
_CCCL_TEMPLATE(class _OtherElementType)
|
|
_CCCL_REQUIRES(__span_array_convertible<_OtherElementType, element_type>)
|
|
_CCCL_HOST_API constexpr span(::std::array<_OtherElementType, _Extent>& __arr) noexcept
|
|
: __data_{__arr.data()}
|
|
{}
|
|
|
|
_CCCL_EXEC_CHECK_DISABLE
|
|
_CCCL_TEMPLATE(class _OtherElementType)
|
|
_CCCL_REQUIRES(__span_array_convertible<const _OtherElementType, element_type>)
|
|
_CCCL_HOST_API constexpr span(const ::std::array<_OtherElementType, _Extent>& __arr) noexcept
|
|
: __data_{__arr.data()}
|
|
{}
|
|
#endif // _CCCL_HAS_HOST_STD_LIB()
|
|
|
|
// NOLINTBEGIN(bugprone-forwarding-reference-overload)
|
|
_CCCL_EXEC_CHECK_DISABLE
|
|
_CCCL_TEMPLATE(class _Range)
|
|
_CCCL_REQUIRES(__span_compatible_range<_Range, element_type>)
|
|
_CCCL_API constexpr explicit span(_Range&& __r)
|
|
: __data_{::cuda::std::ranges::__data_cpo{}(__r)}
|
|
{
|
|
_CCCL_ASSERT(::cuda::std::ranges::__size_cpo{}(__r) == _Extent, "size mismatch in span's constructor (range)");
|
|
}
|
|
// NOLINTEND(bugprone-forwarding-reference-overload)
|
|
|
|
// Deviation from P4144R1 Hana Dusikova's proposed fix: uses initializer_list<_InitListValueType>
|
|
// instead of initializer_list<const _InitListValueType>. The const is redundant because
|
|
// initializer_list<T>::begin() already returns const T*, so initializer_list<const T>::begin()
|
|
// returns const const T* which collapses to const T* — identical behavior. Omitting the const
|
|
// also avoids complications with template argument deduction in the CCCL SFINAE fallback path.
|
|
_CCCL_TEMPLATE(class _InitListValueType, class _Ep = element_type)
|
|
_CCCL_REQUIRES(is_same_v<_InitListValueType, value_type> _CCCL_AND is_const_v<_Ep>)
|
|
_CCCL_API constexpr span(initializer_list<_InitListValueType> __il)
|
|
: __data_{__il.begin()}
|
|
{
|
|
_CCCL_ASSERT(_Extent == __il.size(), "size mismatch in span's constructor (initializer_list)");
|
|
}
|
|
|
|
_CCCL_TEMPLATE(class _OtherElementType, size_t _Extent2 = _Extent)
|
|
_CCCL_REQUIRES((_Extent2 != dynamic_extent) _CCCL_AND __span_array_convertible<_OtherElementType, element_type>)
|
|
_CCCL_API constexpr span(const span<_OtherElementType, _Extent2>& __other) noexcept
|
|
: __data_{__other.data()}
|
|
{}
|
|
|
|
_CCCL_TEMPLATE(class _OtherElementType)
|
|
_CCCL_REQUIRES(__span_array_convertible<_OtherElementType, element_type>)
|
|
_CCCL_API constexpr explicit span(const span<_OtherElementType, dynamic_extent>& __other) noexcept
|
|
: __data_{__other.data()}
|
|
{
|
|
_CCCL_ASSERT(_Extent == __other.size(), "size mismatch in span's constructor (other span)");
|
|
}
|
|
|
|
// ~span() noexcept = default;
|
|
|
|
template <size_t _Count>
|
|
_CCCL_API constexpr span<element_type, _Count> first() const noexcept
|
|
{
|
|
// ternary avoids "pointless comparison of unsigned integer with zero" warning
|
|
static_assert(_Count == 0 ? true : _Count <= _Extent, "span<T, N>::first<Count>(): Count out of range");
|
|
return span<element_type, _Count>{data(), _Count};
|
|
}
|
|
|
|
template <size_t _Count>
|
|
_CCCL_API constexpr span<element_type, _Count> last() const noexcept
|
|
{
|
|
// ternary avoids "pointless comparison of unsigned integer with zero" warning
|
|
static_assert(_Count == 0 ? true : _Count <= _Extent, "span<T, N>::last<Count>(): Count out of range");
|
|
return span<element_type, _Count>{data() + size() - _Count, _Count};
|
|
}
|
|
|
|
_CCCL_API constexpr span<element_type, dynamic_extent> first(size_type __count) const noexcept
|
|
{
|
|
_CCCL_ASSERT(__count <= size(), "span<T, N>::first(count): count out of range");
|
|
return {data(), __count};
|
|
}
|
|
|
|
_CCCL_API constexpr span<element_type, dynamic_extent> last(size_type __count) const noexcept
|
|
{
|
|
_CCCL_ASSERT(__count <= size(), "span<T, N>::last(count): count out of range");
|
|
return {data() + size() - __count, __count};
|
|
}
|
|
|
|
template <size_t _Offset, size_t _Count>
|
|
using __subspan_t = span<element_type, _Count != dynamic_extent ? _Count : _Extent - _Offset>;
|
|
|
|
template <size_t _Offset, size_t _Count = dynamic_extent>
|
|
_CCCL_API constexpr __subspan_t<_Offset, _Count> subspan() const noexcept
|
|
{
|
|
// ternary avoids "pointless comparison of unsigned integer with zero" warning
|
|
if constexpr (_Offset != 0)
|
|
{
|
|
static_assert(_Offset <= _Extent, "span<T, N>::subspan<Offset, Count>(): Offset out of range");
|
|
}
|
|
if constexpr (_Count != 0)
|
|
{
|
|
static_assert(_Count == dynamic_extent || _Count <= _Extent - _Offset,
|
|
"span<T, N>::subspan<Offset, Count>(): Offset + Count out of range");
|
|
}
|
|
return __subspan_t<_Offset, _Count>{data() + _Offset, _Count == dynamic_extent ? size() - _Offset : _Count};
|
|
}
|
|
|
|
_CCCL_API constexpr span<element_type, dynamic_extent>
|
|
subspan(size_type __offset, size_type __count = dynamic_extent) const noexcept
|
|
{
|
|
_CCCL_ASSERT(__offset <= size(), "span<T, N>::subspan(offset, count): offset out of range");
|
|
_CCCL_ASSERT(__count <= size() || __count == dynamic_extent,
|
|
"span<T, N>::subspan(offset, count): count out of range");
|
|
if (__count == dynamic_extent)
|
|
{
|
|
return {data() + __offset, size() - __offset};
|
|
}
|
|
_CCCL_ASSERT(__count <= size() - __offset, "span<T, N>::subspan(offset, count): offset + count out of range");
|
|
return {data() + __offset, __count};
|
|
}
|
|
|
|
_CCCL_API constexpr size_type size() const noexcept
|
|
{
|
|
return _Extent;
|
|
}
|
|
_CCCL_API constexpr size_type size_bytes() const noexcept
|
|
{
|
|
return _Extent * sizeof(element_type);
|
|
}
|
|
[[nodiscard]] _CCCL_API constexpr bool empty() const noexcept
|
|
{
|
|
return _Extent == 0;
|
|
}
|
|
|
|
_CCCL_API constexpr reference operator[](size_type __idx) const noexcept
|
|
{
|
|
_CCCL_ASSERT(__idx < size(), "span<T, N>::operator[](index): index out of range");
|
|
return __data_[__idx];
|
|
}
|
|
|
|
_CCCL_API constexpr reference at(size_type __idx) const
|
|
{
|
|
if (__idx >= size())
|
|
{
|
|
_CCCL_THROW(::std::out_of_range, "span::at");
|
|
}
|
|
return __data_[__idx];
|
|
}
|
|
|
|
_CCCL_API constexpr reference front() const noexcept
|
|
{
|
|
_CCCL_ASSERT(!empty(), "span<T, N>::front() on empty span");
|
|
return __data_[0];
|
|
}
|
|
|
|
_CCCL_API constexpr reference back() const noexcept
|
|
{
|
|
_CCCL_ASSERT(!empty(), "span<T, N>::back() on empty span");
|
|
return __data_[size() - 1];
|
|
}
|
|
|
|
_CCCL_API constexpr pointer data() const noexcept
|
|
{
|
|
return __data_;
|
|
}
|
|
|
|
// [span.iter], span iterator support
|
|
_CCCL_API constexpr iterator begin() const noexcept
|
|
{
|
|
return iterator(data());
|
|
}
|
|
_CCCL_API constexpr iterator end() const noexcept
|
|
{
|
|
return iterator(data() + size());
|
|
}
|
|
_CCCL_API constexpr reverse_iterator rbegin() const noexcept
|
|
{
|
|
return reverse_iterator(end());
|
|
}
|
|
_CCCL_API constexpr reverse_iterator rend() const noexcept
|
|
{
|
|
return reverse_iterator(begin());
|
|
}
|
|
|
|
_CCCL_API inline span<const byte, _Extent * sizeof(element_type)> __as_bytes() const noexcept
|
|
{
|
|
return span<const byte, _Extent * sizeof(element_type)>{reinterpret_cast<const byte*>(data()), size_bytes()};
|
|
}
|
|
|
|
_CCCL_API inline span<byte, _Extent * sizeof(element_type)> __as_writable_bytes() const noexcept
|
|
{
|
|
return span<byte, _Extent * sizeof(element_type)>{reinterpret_cast<byte*>(data()), size_bytes()};
|
|
}
|
|
|
|
private:
|
|
pointer __data_;
|
|
};
|
|
|
|
template <typename _Tp>
|
|
class _CCCL_TYPE_VISIBILITY_DEFAULT span<_Tp, dynamic_extent>
|
|
{
|
|
public:
|
|
// constants and types
|
|
using element_type = _Tp;
|
|
using value_type = remove_cv_t<_Tp>;
|
|
using size_type = size_t;
|
|
using difference_type = ptrdiff_t;
|
|
using pointer = _Tp*;
|
|
using const_pointer = const _Tp*;
|
|
using reference = _Tp&;
|
|
using const_reference = const _Tp&;
|
|
using iterator = __wrap_iter<pointer>;
|
|
using reverse_iterator = ::cuda::std::reverse_iterator<iterator>;
|
|
|
|
static constexpr size_type extent = dynamic_extent;
|
|
|
|
// [span.cons], span constructors, copy, assignment, and destructor
|
|
_CCCL_API constexpr span() noexcept
|
|
: __data_{nullptr}
|
|
, __size_{0}
|
|
{}
|
|
|
|
_CCCL_HIDE_FROM_ABI span(const span&) noexcept = default;
|
|
_CCCL_HIDE_FROM_ABI span& operator=(const span&) noexcept = default;
|
|
|
|
_CCCL_EXEC_CHECK_DISABLE
|
|
_CCCL_TEMPLATE(class _It)
|
|
_CCCL_REQUIRES(__span_compatible_iterator<_It, element_type>)
|
|
_CCCL_API constexpr span(_It __first, size_type __count)
|
|
: __data_{::cuda::std::to_address(__first)}
|
|
, __size_{__count}
|
|
{}
|
|
|
|
_CCCL_EXEC_CHECK_DISABLE
|
|
_CCCL_TEMPLATE(class _It, class _End)
|
|
_CCCL_REQUIRES(__span_compatible_iterator<_It, element_type> _CCCL_AND __span_compatible_sentinel_for<_End, _It>)
|
|
_CCCL_API constexpr span(_It __first, _End __last)
|
|
: __data_(::cuda::std::to_address(__first))
|
|
, __size_(__last - __first)
|
|
{
|
|
_CCCL_ASSERT(__last - __first >= 0, "invalid range in span's constructor (iterator, sentinel)");
|
|
}
|
|
|
|
template <size_t _Sz>
|
|
_CCCL_API constexpr span(type_identity_t<element_type> (&__arr)[_Sz]) noexcept
|
|
: __data_{__arr}
|
|
, __size_{_Sz}
|
|
{}
|
|
|
|
_CCCL_TEMPLATE(class _OtherElementType, size_t _Sz)
|
|
_CCCL_REQUIRES(__span_array_convertible<_OtherElementType, element_type>)
|
|
_CCCL_API constexpr span(array<_OtherElementType, _Sz>& __arr) noexcept
|
|
: __data_{__arr.data()}
|
|
, __size_{_Sz}
|
|
{}
|
|
|
|
_CCCL_TEMPLATE(class _OtherElementType, size_t _Sz)
|
|
_CCCL_REQUIRES(__span_array_convertible<const _OtherElementType, element_type>)
|
|
_CCCL_API constexpr span(const array<_OtherElementType, _Sz>& __arr) noexcept
|
|
: __data_{__arr.data()}
|
|
, __size_{_Sz}
|
|
{}
|
|
|
|
#if _CCCL_HAS_HOST_STD_LIB()
|
|
_CCCL_TEMPLATE(class _OtherElementType, size_t _Sz)
|
|
_CCCL_REQUIRES(__span_array_convertible<_OtherElementType, element_type>)
|
|
_CCCL_HOST_API constexpr span(::std::array<_OtherElementType, _Sz>& __arr) noexcept
|
|
: __data_{__arr.data()}
|
|
, __size_{_Sz}
|
|
{}
|
|
|
|
_CCCL_TEMPLATE(class _OtherElementType, size_t _Sz)
|
|
_CCCL_REQUIRES(__span_array_convertible<const _OtherElementType, element_type>)
|
|
_CCCL_HOST_API constexpr span(const ::std::array<_OtherElementType, _Sz>& __arr) noexcept
|
|
: __data_{__arr.data()}
|
|
, __size_{_Sz}
|
|
{}
|
|
#endif // _CCCL_HAS_HOST_STD_LIB()
|
|
|
|
// NOLINTBEGIN(bugprone-forwarding-reference-overload)
|
|
_CCCL_EXEC_CHECK_DISABLE
|
|
_CCCL_TEMPLATE(class _Range)
|
|
_CCCL_REQUIRES(__span_compatible_range<_Range, element_type>)
|
|
_CCCL_API constexpr span(_Range&& __r)
|
|
: __data_(::cuda::std::ranges::__data_cpo{}(__r))
|
|
, __size_{::cuda::std::ranges::__size_cpo{}(__r)}
|
|
{}
|
|
// NOLINTEND(bugprone-forwarding-reference-overload)
|
|
|
|
// Deviation from P4144R1 Hana Dusikova's proposed fix: uses initializer_list<_InitListValueType>
|
|
// instead of initializer_list<const _InitListValueType>. The const is redundant because
|
|
// initializer_list<T>::begin() already returns const T*, so initializer_list<const T>::begin()
|
|
// returns const const T* which collapses to const T* — identical behavior. Omitting the const
|
|
// also avoids complications with template argument deduction in the CCCL SFINAE fallback path.
|
|
_CCCL_TEMPLATE(class _InitListValueType, class _Ep = element_type)
|
|
_CCCL_REQUIRES(is_same_v<_InitListValueType, value_type> _CCCL_AND is_const_v<_Ep>)
|
|
_CCCL_API constexpr span(initializer_list<_InitListValueType> __il)
|
|
: __data_{__il.begin()}
|
|
, __size_{__il.size()}
|
|
{}
|
|
|
|
_CCCL_TEMPLATE(class _OtherElementType, size_t _OtherExtent)
|
|
_CCCL_REQUIRES(__span_array_convertible<_OtherElementType, element_type>)
|
|
_CCCL_API constexpr span(const span<_OtherElementType, _OtherExtent>& __other) noexcept
|
|
: __data_{__other.data()}
|
|
, __size_{__other.size()}
|
|
{}
|
|
|
|
// ~span() noexcept = default;
|
|
|
|
template <size_t _Count>
|
|
_CCCL_API constexpr span<element_type, _Count> first() const noexcept
|
|
{
|
|
// ternary avoids "pointless comparison of unsigned integer with zero" warning
|
|
_CCCL_ASSERT(_Count == 0 ? true : _Count <= size(), "span<T>::first<Count>(): Count out of range");
|
|
return span<element_type, _Count>{data(), _Count};
|
|
}
|
|
|
|
template <size_t _Count>
|
|
_CCCL_API constexpr span<element_type, _Count> last() const noexcept
|
|
{
|
|
// ternary avoids "pointless comparison of unsigned integer with zero" warning
|
|
_CCCL_ASSERT(_Count == 0 ? true : _Count <= size(), "span<T>::last<Count>(): Count out of range");
|
|
return span<element_type, _Count>{data() + size() - _Count, _Count};
|
|
}
|
|
|
|
_CCCL_API constexpr span<element_type, dynamic_extent> first(size_type __count) const noexcept
|
|
{
|
|
_CCCL_ASSERT(__count <= size(), "span<T>::first(count): count out of range");
|
|
return {data(), __count};
|
|
}
|
|
|
|
_CCCL_API constexpr span<element_type, dynamic_extent> last(size_type __count) const noexcept
|
|
{
|
|
_CCCL_ASSERT(__count <= size(), "span<T>::last(count): count out of range");
|
|
return {data() + size() - __count, __count};
|
|
}
|
|
|
|
template <size_t _Offset, size_t _Count>
|
|
using __subspan_t = span<element_type, _Count>;
|
|
|
|
template <size_t _Offset, size_t _Count = dynamic_extent>
|
|
_CCCL_API constexpr __subspan_t<_Offset, _Count> subspan() const noexcept
|
|
{
|
|
// ternary avoids "pointless comparison of unsigned integer with zero" warning
|
|
_CCCL_ASSERT(_Offset == 0 ? true : _Offset <= size(), "span<T>::subspan<Offset, Count>(): Offset out of range");
|
|
_CCCL_ASSERT(_Count == dynamic_extent || (_Count == 0 ? true : _Count <= size() - _Offset),
|
|
"span<T>::subspan<Offset, Count>(): Offset + Count out of range");
|
|
return __subspan_t<_Offset, _Count>{data() + _Offset, _Count == dynamic_extent ? size() - _Offset : _Count};
|
|
}
|
|
|
|
constexpr span<element_type, dynamic_extent> _CCCL_API inline subspan(
|
|
size_type __offset, size_type __count = dynamic_extent) const noexcept
|
|
{
|
|
_CCCL_ASSERT(__offset <= size(), "span<T>::subspan(offset, count): offset out of range");
|
|
_CCCL_ASSERT(__count <= size() || __count == dynamic_extent, "span<T>::subspan(offset, count): count out of range");
|
|
if (__count == dynamic_extent)
|
|
{
|
|
return {data() + __offset, size() - __offset};
|
|
}
|
|
_CCCL_ASSERT(__count <= size() - __offset, "span<T>::subspan(offset, count): offset + count out of range");
|
|
return {data() + __offset, __count};
|
|
}
|
|
|
|
_CCCL_API constexpr size_type size() const noexcept
|
|
{
|
|
return __size_;
|
|
}
|
|
_CCCL_API constexpr size_type size_bytes() const noexcept
|
|
{
|
|
return __size_ * sizeof(element_type);
|
|
}
|
|
[[nodiscard]] _CCCL_API constexpr bool empty() const noexcept
|
|
{
|
|
return __size_ == 0;
|
|
}
|
|
|
|
_CCCL_API constexpr reference operator[](size_type __idx) const noexcept
|
|
{
|
|
_CCCL_ASSERT(__idx < size(), "span<T>::operator[](index): index out of range");
|
|
return __data_[__idx];
|
|
}
|
|
|
|
_CCCL_API constexpr reference at(size_type __idx) const
|
|
{
|
|
if (__idx >= size())
|
|
{
|
|
_CCCL_THROW(::std::out_of_range, "span::at");
|
|
}
|
|
return __data_[__idx];
|
|
}
|
|
|
|
_CCCL_API constexpr reference front() const noexcept
|
|
{
|
|
_CCCL_ASSERT(!empty(), "span<T>::front() on empty span");
|
|
return __data_[0];
|
|
}
|
|
|
|
_CCCL_API constexpr reference back() const noexcept
|
|
{
|
|
_CCCL_ASSERT(!empty(), "span<T>::back() on empty span");
|
|
return __data_[size() - 1];
|
|
}
|
|
|
|
_CCCL_API constexpr pointer data() const noexcept
|
|
{
|
|
return __data_;
|
|
}
|
|
|
|
// [span.iter], span iterator support
|
|
_CCCL_API constexpr iterator begin() const noexcept
|
|
{
|
|
return iterator(data());
|
|
}
|
|
_CCCL_API constexpr iterator end() const noexcept
|
|
{
|
|
return iterator(data() + size());
|
|
}
|
|
_CCCL_API constexpr reverse_iterator rbegin() const noexcept
|
|
{
|
|
return reverse_iterator(end());
|
|
}
|
|
_CCCL_API constexpr reverse_iterator rend() const noexcept
|
|
{
|
|
return reverse_iterator(begin());
|
|
}
|
|
|
|
_CCCL_API inline span<const byte, dynamic_extent> __as_bytes() const noexcept
|
|
{
|
|
return span<const byte, dynamic_extent>{reinterpret_cast<const byte*>(data()), size_bytes()};
|
|
}
|
|
|
|
_CCCL_API inline span<byte, dynamic_extent> __as_writable_bytes() const noexcept
|
|
{
|
|
return span<byte, dynamic_extent>{reinterpret_cast<byte*>(data()), size_bytes()};
|
|
}
|
|
|
|
private:
|
|
pointer __data_;
|
|
size_type __size_;
|
|
};
|
|
|
|
// as_bytes & as_writable_bytes
|
|
template <class _Tp, size_t _Extent>
|
|
_CCCL_API inline auto as_bytes(span<_Tp, _Extent> __s) noexcept
|
|
{
|
|
return __s.__as_bytes();
|
|
}
|
|
|
|
_CCCL_TEMPLATE(class _Tp, size_t _Extent)
|
|
_CCCL_REQUIRES((!is_const<_Tp>::value))
|
|
_CCCL_API inline auto as_writable_bytes(span<_Tp, _Extent> __s) noexcept
|
|
{
|
|
return __s.__as_writable_bytes();
|
|
}
|
|
|
|
// Deduction guides
|
|
template <class _Tp, size_t _Sz>
|
|
_CCCL_DEDUCTION_GUIDE_ATTRIBUTES span(_Tp (&)[_Sz]) -> span<_Tp, _Sz>;
|
|
|
|
template <class _Tp, size_t _Sz>
|
|
_CCCL_DEDUCTION_GUIDE_ATTRIBUTES span(array<_Tp, _Sz>&) -> span<_Tp, _Sz>;
|
|
|
|
template <class _Tp, size_t _Sz>
|
|
_CCCL_DEDUCTION_GUIDE_ATTRIBUTES span(const array<_Tp, _Sz>&) -> span<const _Tp, _Sz>;
|
|
|
|
#if _CCCL_HAS_HOST_STD_LIB()
|
|
template <class _Tp, size_t _Sz>
|
|
_CCCL_DEDUCTION_GUIDE_ATTRIBUTES span(::std::array<_Tp, _Sz>&) -> span<_Tp, _Sz>;
|
|
|
|
template <class _Tp, size_t _Sz>
|
|
_CCCL_DEDUCTION_GUIDE_ATTRIBUTES span(const ::std::array<_Tp, _Sz>&) -> span<const _Tp, _Sz>;
|
|
#endif // _CCCL_HAS_HOST_STD_LIB()
|
|
|
|
_CCCL_TEMPLATE(class _It, class _EndOrSize)
|
|
_CCCL_REQUIRES(contiguous_iterator<_It>)
|
|
_CCCL_DEDUCTION_GUIDE_ATTRIBUTES span(_It, _EndOrSize)
|
|
-> span<remove_reference_t<iter_reference_t<_It>>, __maybe_static_ext<_EndOrSize>>;
|
|
|
|
_CCCL_TEMPLATE(class _Range)
|
|
_CCCL_REQUIRES(::cuda::std::ranges::contiguous_range<_Range>)
|
|
_CCCL_DEDUCTION_GUIDE_ATTRIBUTES span(_Range&&)
|
|
-> span<remove_reference_t<::cuda::std::ranges::range_reference_t<_Range>>>;
|
|
|
|
_CCCL_END_NAMESPACE_CUDA_STD
|
|
|
|
_CCCL_BEGIN_NAMESPACE_CUDA_STD_RANGES
|
|
template <class _Tp, size_t _Extent>
|
|
inline constexpr bool enable_borrowed_range<span<_Tp, _Extent>> = true;
|
|
|
|
template <class _Tp, size_t _Extent>
|
|
inline constexpr bool enable_view<span<_Tp, _Extent>> = true;
|
|
_CCCL_END_NAMESPACE_CUDA_STD_RANGES
|
|
|
|
#include <cuda/std/__cccl/epilogue.h>
|
|
|
|
#endif // _CUDA_STD_SPAN
|