//===----------------------------------------------------------------------===// // // 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) 2026 NVIDIA CORPORATION & AFFILIATES. // //===----------------------------------------------------------------------===// #ifndef _CUDA___CONTAINER_BUFFER_H #define _CUDA___CONTAINER_BUFFER_H #include #if defined(_CCCL_IMPLICIT_SYSTEM_HEADER_GCC) # pragma GCC system_header #elif defined(_CCCL_IMPLICIT_SYSTEM_HEADER_CLANG) # pragma clang system_header #elif defined(_CCCL_IMPLICIT_SYSTEM_HEADER_MSVC) # pragma system_header #endif // no system header #if _CCCL_HAS_CTK() # if _CCCL_CUDA_COMPILATION() # include # endif // _CCCL_CUDA_COMPILATION() # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include //! @file //! @brief The \c buffer class provides a container of contiguous memory _CCCL_BEGIN_NAMESPACE_CUDA template inline constexpr bool __buffer_compatible_env = ::cuda::std::is_same_v<::cuda::std::decay_t<_Env>, ::cuda::std::execution::env<>> || ::cuda::std::execution::__queryable_with; _CCCL_BEGIN_NAMESPACE_ABI_VER4_BUMP //! @rst //! .. _libcudacxx-containers-buffer: //! //! buffer //! ------------- //! //! ``buffer`` is a container that provides resizable typed storage allocated //! from a given :ref:`memory resource //! `. It handles alignment, //! release and growth of the allocation. The elements are initialized during //! construction, which may require a kernel launch. //! //! In addition to being type-safe, ``buffer`` also takes a set of //! :ref:`properties ` to //! ensure that e.g. execution space constraints are checked at compile time. //! However, only stateless properties can be forwarded. To use a stateful //! property, implement :ref:`get_property(const buffer&, Property) //! `. //! //! @endrst //! @tparam _Tp the type to be stored in the buffer //! @tparam _Properties... The properties the allocated memory satisfies template class buffer { public: using value_type = _Tp; using reference = _Tp&; using const_reference = const _Tp&; using pointer = _Tp*; using const_pointer = const _Tp*; using iterator = ::cuda::heterogeneous_iterator<_Tp, _Properties...>; using const_iterator = ::cuda::heterogeneous_iterator; using reverse_iterator = ::cuda::std::reverse_iterator; using const_reverse_iterator = ::cuda::std::reverse_iterator; using size_type = ::cuda::std::size_t; using difference_type = ::cuda::std::ptrdiff_t; using properties_list = ::cuda::mr::properties_list<_Properties...>; using __buffer_t = ::cuda::__uninitialized_async_buffer<_Tp, _Properties...>; using __resource_t = ::cuda::mr::any_resource<_Properties...>; using __resource_ref_t = ::cuda::mr::resource_ref<_Properties...>; template friend class buffer; // For now we require trivially copyable type to simplify the implementation static_assert(::cuda::is_trivially_copyable_v<_Tp>, "cuda::buffer requires T to be trivially copyable."); // At least one of the properties must signal an execution space static_assert(::cuda::mr::__contains_execution_space_property<_Properties...>, "The properties of cuda::buffer must contain at " "least one execution space property!"); private: __buffer_t __buf_; # ifndef _CCCL_DOXYGEN_INVOKED _CCCL_HOST_API explicit buffer(__buffer_t&& __buf) noexcept : __buf_(::cuda::std::move(__buf)) {} # endif // _CCCL_DOXYGEN_INVOKED //! @brief Helper to check container is compatible with this buffer template [[nodiscard]] static constexpr bool __compatible_range() noexcept { return ::cuda::std::ranges::__container_compatible_range<_Range, _Tp>; } //! @brief Helper to check whether a different buffer still satisfies all //! properties of this one template [[nodiscard]] static constexpr bool __properties_match() noexcept { return ::cuda::std::__type_set_contains_v<::cuda::std::__make_type_set<_OtherProperties...>, _Properties...>; } //! @brief Helper to return an resource_ref to the currently used resource. //! Used to grow the buffer __resource_ref_t __borrow_resource() const noexcept { return const_cast<__resource_t&>(__buf_.memory_resource()); } template static size_t __alignment_from_env(const _Env& __env) { const auto __align = ::cuda::__call_or(::cuda::allocation_alignment, alignof(_Tp), __env); ::cuda::__validate_allocation_alignment(__align, alignof(_Tp)); return __align; } //! @brief Copies \p __count elements from `[__first, __last)` to \p __dest, //! where \p __first and \p __dest reside in the different memory spaces //! @param __first Pointer to the start of the input segment. //! @param __last Pointer to the end of the input segment. //! @param __dest Pointer to the start of the output segment. //! @param __count The number of elements to be copied. //! @note This function is inherently asynchronous. We need to ensure that the //! memory pointed to by \p __first and //! \p __last lives long enough template _CCCL_HOST_API void __copy_cross(_Iter __first, [[maybe_unused]] _Iter __last, pointer __dest, size_type __count) { if (__count == 0) { return; } static_assert(::cuda::std::contiguous_iterator<_Iter>, "Non contiguous iterators are not supported"); // TODO use batched memcpy for non-contiguous iterators, it allows to // specify stream ordered access ::cuda::__ensure_current_context __guard(__buf_.stream()); ::cuda::__driver::__memcpyAsync( __dest, ::cuda::std::to_address(__first), sizeof(_Tp) * __count, __buf_.stream().get()); } public: //! @brief Copy-constructs from a buffer //! @param __other The other buffer. _CCCL_HOST_API explicit buffer(const buffer& __other) : __buf_(__other.memory_resource(), __other.stream(), __other.size(), __other.__buf_.alignment()) { this->__copy_cross( __other.__unwrapped_begin(), __other.__unwrapped_end(), __unwrapped_begin(), __other.size()); } //! @brief Move-constructs from a buffer //! @param __other The other buffer. After move construction, the other buffer //! can only be assigned to or destroyed. _CCCL_HOST_API buffer(buffer&& __other) noexcept : __buf_(::cuda::std::move(__other.__buf_)) {} //! @brief Copy-constructs from a buffer with matching properties //! @param __other The other buffer. _CCCL_TEMPLATE(class... _OtherProperties) _CCCL_REQUIRES((__properties_match<_OtherProperties...>())) _CCCL_HOST_API explicit buffer(const buffer<_Tp, _OtherProperties...>& __other) : __buf_(__other.memory_resource(), __other.stream(), __other.size(), __other.__buf_.alignment()) { this->__copy_cross( __other.__unwrapped_begin(), __other.__unwrapped_end(), __unwrapped_begin(), __other.size()); } //! @brief Move-constructs from a buffer with matching properties //! @param __other The other buffer. After move construction, the other buffer //! can only be assigned to or destroyed. _CCCL_TEMPLATE(class... _OtherProperties) _CCCL_REQUIRES((__properties_match<_OtherProperties...>())) _CCCL_HOST_API buffer(buffer<_Tp, _OtherProperties...>&& __other) noexcept : __buf_(::cuda::std::move(__other.__buf_)) {} //! @brief Constructs an empty buffer using an environment //! @param __stream The stream used for allocations. //! @param __resource The memory resource used for allocations. //! @param __env The environment providing the needed information //! @note No memory is allocated. _CCCL_TEMPLATE(class _Resource, class _Env = ::cuda::std::execution::env<>) _CCCL_REQUIRES( ::cuda::mr::synchronous_resource<::cuda::std::decay_t<_Resource>> _CCCL_AND __buffer_compatible_env<_Env>) _CCCL_HOST_API buffer(::cuda::stream_ref __stream, _Resource&& __resource, [[maybe_unused]] const _Env& __env = {}) : __buf_(::cuda::mr::__adapt_if_synchronous(::cuda::std::forward<_Resource>(__resource)), __stream, 0, __alignment_from_env(__env)) { static_assert(::cuda::std::is_copy_constructible_v<::cuda::std::decay_t<_Resource>>, "Buffer owns a copy of the memory resource, which means it must be copy constructible. " "cuda::mr::shared_resource can be used to attach shared ownership to a resource type."); } //! @brief Constructs a buffer of size \p __size using a memory and leaves all //! elements uninitialized //! @param __stream The stream used for allocations. //! @param __resource The memory resource used for allocations. //! @param __env The environment used to query the memory resource. //! @param __size The size of the buffer. //! @warning This constructor does *NOT* initialize any elements. It is the //! user's responsibility to ensure that the elements within `[vec.begin(), //! vec.end())` are properly initialized, e.g with //! `cuda::std::uninitialized_copy`. At the destruction of the \c buffer all //! elements in the range `[vec.begin(), vec.end())` will be destroyed. _CCCL_TEMPLATE(class _Resource, class _Env = ::cuda::std::execution::env<>) _CCCL_REQUIRES( ::cuda::mr::synchronous_resource<::cuda::std::decay_t<_Resource>> _CCCL_AND __buffer_compatible_env<_Env>) _CCCL_HOST_API explicit buffer( ::cuda::stream_ref __stream, _Resource&& __resource, const size_type __size, ::cuda::no_init_t, [[maybe_unused]] const _Env& __env = {}) : __buf_(::cuda::mr::__adapt_if_synchronous(::cuda::std::forward<_Resource>(__resource)), __stream, __size, __alignment_from_env(__env)) { static_assert(::cuda::std::is_copy_constructible_v<::cuda::std::decay_t<_Resource>>, "Buffer owns a copy of the memory resource, which means it must be copy constructible. " "cuda::mr::shared_resource can be used to attach shared ownership to a resource type."); } //! @brief Constructs a buffer using a memory resource and copy-constructs all //! elements from the forward range //! ``[__first, __last)`` //! @param __stream The stream used for allocations. //! @param __resource The memory resource used for allocations. //! @param __env The environment used to query the memory resource. //! @param __first The start of the input sequence. //! @param __last The end of the input sequence. //! @note If `__first == __last` then no memory is allocated _CCCL_TEMPLATE(class _Iter, class _Resource, class _Env = ::cuda::std::execution::env<>) _CCCL_REQUIRES(::cuda::mr::synchronous_resource<::cuda::std::decay_t<_Resource>> _CCCL_AND ::cuda::std::__has_forward_traversal<_Iter>) _CCCL_HOST_API buffer(::cuda::stream_ref __stream, _Resource&& __resource, _Iter __first, _Iter __last, [[maybe_unused]] const _Env& __env = {}) : __buf_(::cuda::mr::__adapt_if_synchronous(::cuda::std::forward<_Resource>(__resource)), __stream, static_cast(::cuda::std::distance(__first, __last)), __alignment_from_env(__env)) { static_assert(::cuda::std::is_copy_constructible_v<::cuda::std::decay_t<_Resource>>, "Buffer owns a copy of the memory resource, which means it must be copy constructible. " "cuda::mr::shared_resource can be used to attach shared ownership to a resource type."); this->__copy_cross<_Iter>(__first, __last, __unwrapped_begin(), __buf_.size()); } //! @brief Constructs a buffer using a memory resource and copy-constructs all //! elements from \p __ilist //! @param __stream The stream used for allocations. //! @param __resource The memory resource used for allocations. //! @param __env The environment used to query the memory resource. //! @param __ilist The initializer_list being copied into the buffer. //! @note If `__ilist.size() == 0` then no memory is allocated _CCCL_TEMPLATE(class _Resource, class _Env = ::cuda::std::execution::env<>) _CCCL_REQUIRES( ::cuda::mr::synchronous_resource<::cuda::std::decay_t<_Resource>> _CCCL_AND __buffer_compatible_env<_Env>) _CCCL_HOST_API buffer(::cuda::stream_ref __stream, _Resource&& __resource, ::cuda::std::initializer_list<_Tp> __ilist, [[maybe_unused]] const _Env& __env = {}) : __buf_(::cuda::mr::__adapt_if_synchronous(::cuda::std::forward<_Resource>(__resource)), __stream, __ilist.size(), __alignment_from_env(__env)) { static_assert(::cuda::std::is_copy_constructible_v<::cuda::std::decay_t<_Resource>>, "Buffer owns a copy of the memory resource, which means it must be copy constructible. " "cuda::mr::shared_resource can be used to attach shared ownership to a resource type."); this->__copy_cross(__ilist.begin(), __ilist.end(), __unwrapped_begin(), __buf_.size()); } //! @brief Constructs a buffer using a memory resource and an input range //! @param __stream The stream used for allocations. //! @param __resource The memory resource used for allocations. //! @param __env The environment used to query the memory resource. //! @param __range The input range to be moved into the buffer. //! @note If `__range.size() == 0` then no memory is allocated. _CCCL_TEMPLATE(class _Range, class _Resource, class _Env = ::cuda::std::execution::env<>) _CCCL_REQUIRES( ::cuda::mr::synchronous_resource<::cuda::std::decay_t<_Resource>> _CCCL_AND(__compatible_range<_Range>()) _CCCL_AND ::cuda::std::ranges::forward_range<_Range> _CCCL_AND ::cuda::std::ranges::sized_range<_Range>) _CCCL_HOST_API buffer(::cuda::stream_ref __stream, _Resource&& __resource, _Range&& __range, [[maybe_unused]] const _Env& __env = {}) : __buf_(::cuda::mr::__adapt_if_synchronous(::cuda::std::forward<_Resource>(__resource)), __stream, static_cast(::cuda::std::ranges::__size_cpo{}(__range)), __alignment_from_env(__env)) { static_assert(::cuda::std::is_copy_constructible_v<::cuda::std::decay_t<_Resource>>, "Buffer owns a copy of the memory resource, which means it must be copy constructible. " "cuda::mr::shared_resource can be used to attach shared ownership to a resource type."); using _Iter = ::cuda::std::ranges::iterator_t<_Range>; this->__copy_cross<_Iter>( ::cuda::std::ranges::__begin_cpo{}(__range), ::cuda::std::ranges::__unwrap_end(__range), __unwrapped_begin(), __buf_.size()); } # ifndef _CCCL_DOXYGEN_INVOKED // doxygen conflates the overloads _CCCL_TEMPLATE(class _Range, class _Resource, class _Env = ::cuda::std::execution::env<>) _CCCL_REQUIRES( ::cuda::mr::synchronous_resource<::cuda::std::decay_t<_Resource>> _CCCL_AND(__compatible_range<_Range>()) _CCCL_AND ::cuda::std::ranges::forward_range<_Range> _CCCL_AND(!::cuda::std::ranges::sized_range<_Range>)) _CCCL_HOST_API buffer(::cuda::stream_ref __stream, _Resource&& __resource, _Range&& __range, [[maybe_unused]] const _Env& __env = {}) : __buf_(::cuda::mr::__adapt_if_synchronous(::cuda::std::forward<_Resource>(__resource)), __stream, static_cast(::cuda::std::ranges::__distance_cpo{}( ::cuda::std::ranges::__begin_cpo{}(__range), ::cuda::std::ranges::__end_cpo{}(__range))), __alignment_from_env(__env)) { static_assert(::cuda::std::is_copy_constructible_v<::cuda::std::decay_t<_Resource>>, "Buffer owns a copy of the memory resource, which means it must be copy constructible. " "cuda::mr::shared_resource can be used to attach shared ownership to a resource type."); using _Iter = ::cuda::std::ranges::iterator_t<_Range>; this->__copy_cross<_Iter>( ::cuda::std::ranges::__begin_cpo{}(__range), ::cuda::std::ranges::__unwrap_end(__range), __unwrapped_begin(), __buf_.size()); } # endif // _CCCL_DOXYGEN_INVOKED //! @brief Returns an iterator to the first element of the buffer. If the //! buffer is empty, the returned iterator will be equal to end(). [[nodiscard]] _CCCL_HOST_API iterator begin() noexcept { return iterator{__buf_.data()}; } //! @brief Returns an immutable iterator to the first element of the buffer. //! If the buffer is empty, the returned iterator will be equal to end(). [[nodiscard]] _CCCL_HOST_API const_iterator begin() const noexcept { return const_iterator{__buf_.data()}; } //! @brief Returns an immutable iterator to the first element of the buffer. //! If the buffer is empty, the returned iterator will be equal to end(). [[nodiscard]] _CCCL_HOST_API const_iterator cbegin() const noexcept { return const_iterator{__buf_.data()}; } //! @brief Returns an iterator to the element following the last element of //! the buffer. This element acts as a placeholder; attempting to access it //! results in undefined behavior. [[nodiscard]] _CCCL_HOST_API iterator end() noexcept { return iterator{__buf_.data() + __buf_.size()}; } //! @brief Returns an immutable iterator to the element following the last //! element of the buffer. This element acts as a placeholder; attempting to //! access it results in undefined behavior. [[nodiscard]] _CCCL_HOST_API const_iterator end() const noexcept { return const_iterator{__buf_.data() + __buf_.size()}; } //! @brief Returns an immutable iterator to the element following the last //! element of the buffer. This element acts as a placeholder; attempting to //! access it results in undefined behavior. [[nodiscard]] _CCCL_HOST_API const_iterator cend() const noexcept { return const_iterator{__buf_.data() + __buf_.size()}; } //! @brief Returns a reverse iterator to the first element of the reversed //! buffer. It corresponds to the last element of the non-reversed buffer. If //! the buffer is empty, the returned iterator is equal to rend(). [[nodiscard]] _CCCL_HOST_API reverse_iterator rbegin() noexcept { return reverse_iterator{end()}; } //! @brief Returns an immutable reverse iterator to the first element of the //! reversed buffer. It corresponds to the last element of the non-reversed //! buffer. If the buffer is empty, the returned iterator is equal to rend(). [[nodiscard]] _CCCL_HOST_API const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator{end()}; } //! @brief Returns an immutable reverse iterator to the first element of the //! reversed buffer. It corresponds to the last element of the non-reversed //! buffer. If the buffer is empty, the returned iterator is equal to rend(). [[nodiscard]] _CCCL_HOST_API const_reverse_iterator crbegin() const noexcept { return const_reverse_iterator{end()}; } //! @brief Returns a reverse iterator to the element following the last //! element of the reversed buffer. It corresponds to the element preceding //! the first element of the non-reversed buffer. This element acts as a //! placeholder, attempting to access it results in undefined behavior. [[nodiscard]] _CCCL_HOST_API reverse_iterator rend() noexcept { return reverse_iterator{begin()}; } //! @brief Returns an immutable reverse iterator to the element following the //! last element of the reversed buffer. It corresponds to the element //! preceding the first element of the non-reversed buffer. This element acts //! as a placeholder, attempting to access it results in undefined behavior. [[nodiscard]] _CCCL_HOST_API const_reverse_iterator rend() const noexcept { return const_reverse_iterator{begin()}; } //! @brief Returns an immutable reverse iterator to the element following the //! last element of the reversed buffer. It corresponds to the element //! preceding the first element of the non-reversed buffer. This element acts //! as a placeholder, attempting to access it results in undefined behavior. [[nodiscard]] _CCCL_HOST_API const_reverse_iterator crend() const noexcept { return const_reverse_iterator{begin()}; } //! @brief Returns a pointer to the first element of the buffer. If the buffer //! has not allocated memory the pointer will be null. [[nodiscard]] _CCCL_HOST_API pointer data() noexcept { return __buf_.data(); } //! @brief Returns a pointer to the first element of the buffer. If the buffer //! has not allocated memory the pointer will be null. [[nodiscard]] _CCCL_HOST_API const_pointer data() const noexcept { return __buf_.data(); } //! @brief Gets a reference to the element at index `__i`. Requires ``cuda::host_accessible`` property. //! @throw std::out_of_range if `__i < size()`. //! @since CCCL 3.4, CUDA Toolkit 13.4. _CCCL_TEMPLATE(bool _IsHostAccessible = ::cuda::mr::__is_host_accessible<_Properties...>) _CCCL_REQUIRES(_IsHostAccessible) [[nodiscard]] _CCCL_HOST_API _Tp& at(size_type __i) { if (__i >= size()) { _CCCL_THROW(::std::out_of_range, "__i must be less than size()"); } return data()[__i]; } //! @overload _CCCL_TEMPLATE(bool _IsHostAccessible = ::cuda::mr::__is_host_accessible<_Properties...>) _CCCL_REQUIRES(_IsHostAccessible) [[nodiscard]] _CCCL_HOST_API const _Tp& at(size_type __i) const { if (__i >= size()) { _CCCL_THROW(::std::out_of_range, "__i must be less than size()"); } return data()[__i]; } //! @brief Gets a reference to the element at index `__i`. Requires ``cuda::host_accessible`` property. //! @pre `__i < size()`. //! @since CCCL 3.4, CUDA Toolkit 13.4. _CCCL_TEMPLATE(bool _IsHostAccessible = ::cuda::mr::__is_host_accessible<_Properties...>) _CCCL_REQUIRES(_IsHostAccessible) [[nodiscard]] _CCCL_HOST_API _Tp& operator[](size_type __i) noexcept { _CCCL_ASSERT(__i < size(), "__i must be less than size()"); return data()[__i]; } //! @overload _CCCL_TEMPLATE(bool _IsHostAccessible = ::cuda::mr::__is_host_accessible<_Properties...>) _CCCL_REQUIRES(_IsHostAccessible) [[nodiscard]] _CCCL_HOST_API const _Tp& operator[](size_type __i) const noexcept { _CCCL_ASSERT(__i < size(), "__i must be less than size()"); return data()[__i]; } //! @brief Gets a reference to the first element. Requires ``cuda::host_accessible`` property. //! @pre `!empty()`. //! @since CCCL 3.4, CUDA Toolkit 13.4. _CCCL_TEMPLATE(bool _IsHostAccessible = ::cuda::mr::__is_host_accessible<_Properties...>) _CCCL_REQUIRES(_IsHostAccessible) [[nodiscard]] _CCCL_HOST_API _Tp& front() noexcept { _CCCL_ASSERT(!empty(), "the buffer must not be empty"); return data()[0]; } //! @overload _CCCL_TEMPLATE(bool _IsHostAccessible = ::cuda::mr::__is_host_accessible<_Properties...>) _CCCL_REQUIRES(_IsHostAccessible) [[nodiscard]] _CCCL_HOST_API const _Tp& front() const noexcept { _CCCL_ASSERT(!empty(), "the buffer must not be empty"); return data()[0]; } //! @brief Gets a reference to the last element. Requires ``cuda::host_accessible`` property. //! @pre `!empty()`. //! @since CCCL 3.4, CUDA Toolkit 13.4. _CCCL_TEMPLATE(bool _IsHostAccessible = ::cuda::mr::__is_host_accessible<_Properties...>) _CCCL_REQUIRES(_IsHostAccessible) [[nodiscard]] _CCCL_HOST_API _Tp& back() noexcept { _CCCL_ASSERT(!empty(), "the buffer must not be empty"); return data()[size() - 1]; } //! @overload _CCCL_TEMPLATE(bool _IsHostAccessible = ::cuda::mr::__is_host_accessible<_Properties...>) _CCCL_REQUIRES(_IsHostAccessible) [[nodiscard]] _CCCL_HOST_API const _Tp& back() const noexcept { _CCCL_ASSERT(!empty(), "the buffer must not be empty"); return data()[size() - 1]; } //! @brief Returns a span over the first \p __count elements. //! @param __count Number of elements in the returned span. //! @pre `__count <= size()` [[nodiscard]] _CCCL_HOST_API ::cuda::std::span<_Tp> first(size_type __count) noexcept { _CCCL_ASSERT(__count <= size(), "cuda::buffer::first(count): count out of range"); return {data(), __count}; } //! @overload [[nodiscard]] _CCCL_HOST_API ::cuda::std::span first(size_type __count) const noexcept { _CCCL_ASSERT(__count <= size(), "cuda::buffer::first(count): count out of range"); return {data(), __count}; } //! @brief Returns a span over the last \p __count elements. //! @param __count Number of elements in the returned span. //! @pre `__count <= size()` [[nodiscard]] _CCCL_HOST_API ::cuda::std::span<_Tp> last(size_type __count) noexcept { _CCCL_ASSERT(__count <= size(), "cuda::buffer::last(count): count out of range"); return {data() + size() - __count, __count}; } //! @overload [[nodiscard]] _CCCL_HOST_API ::cuda::std::span last(size_type __count) const noexcept { _CCCL_ASSERT(__count <= size(), "cuda::buffer::last(count): count out of range"); return {data() + size() - __count, __count}; } //! @brief Returns a span over a subset of the buffer. //! @param __offset Index of the first element in the returned span. //! @param __count Number of elements. Defaults to `dynamic_extent`, meaning //! all elements from \p __offset to the end. //! @pre `__offset <= size()` //! @pre `__count <= size() - __offset || __count == dynamic_extent` [[nodiscard]] _CCCL_HOST_API ::cuda::std::span<_Tp> subspan(size_type __offset, size_type __count = ::cuda::std::dynamic_extent) noexcept { _CCCL_ASSERT(__offset <= size(), "cuda::buffer::subspan(offset, count): offset out of range"); if (__count == ::cuda::std::dynamic_extent) { return {data() + __offset, size() - __offset}; } _CCCL_ASSERT(__count <= size() - __offset, "cuda::buffer::subspan(offset, count): count out of range"); return {data() + __offset, __count}; } //! @overload [[nodiscard]] _CCCL_HOST_API ::cuda::std::span subspan(size_type __offset, size_type __count = ::cuda::std::dynamic_extent) const noexcept { _CCCL_ASSERT(__offset <= size(), "cuda::buffer::subspan(offset, count): offset out of range"); if (__count == ::cuda::std::dynamic_extent) { return {data() + __offset, size() - __offset}; } _CCCL_ASSERT(__count <= size() - __offset, "cuda::buffer::subspan(offset, count): count out of range"); return {data() + __offset, __count}; } # ifndef _CCCL_DOXYGEN_INVOKED //! @brief Returns a pointer to the first element of the buffer. If the buffer //! is empty, the returned pointer will be null. [[nodiscard]] _CCCL_HOST_API pointer __unwrapped_begin() noexcept { return __buf_.data(); } //! @brief Returns a const pointer to the first element of the buffer. If the //! buffer is empty, the returned pointer will be null. [[nodiscard]] _CCCL_HOST_API const_pointer __unwrapped_begin() const noexcept { return __buf_.data(); } //! @brief Returns a pointer to the element following the last element of the //! buffer. This element acts as a placeholder; attempting to access it //! results in undefined behavior. [[nodiscard]] _CCCL_HOST_API pointer __unwrapped_end() noexcept { return __buf_.data() + __buf_.size(); } //! @brief Returns a const pointer to the element following the last element //! of the buffer. This element acts as a placeholder; attempting to access it //! results in undefined behavior. [[nodiscard]] _CCCL_HOST_API const_pointer __unwrapped_end() const noexcept { return __buf_.data() + __buf_.size(); } # endif // _CCCL_DOXYGEN_INVOKED //! @brief Returns a reference to the \p __n 'th element of the async_vector //! @param __n The index of the element we want to access //! @note Does not synchronize with the stored stream [[nodiscard]] _CCCL_HOST_API reference get_unsynchronized(const size_type __n) noexcept { _CCCL_ASSERT(__n < __buf_.size(), "cuda::buffer::get_unsynchronized out of range!"); return __unwrapped_begin()[__n]; } //! @brief Returns a reference to the \p __n 'th element of the async_vector //! @param __n The index of the element we want to access //! @note Does not synchronize with the stored stream [[nodiscard]] _CCCL_HOST_API const_reference get_unsynchronized(const size_type __n) const noexcept { _CCCL_ASSERT(__n < __buf_.size(), "cuda::buffer::get_unsynchronized out of range!"); return __unwrapped_begin()[__n]; } //! @brief Returns the current number of elements stored in the buffer. [[nodiscard]] _CCCL_HOST_API size_type size() const noexcept { return __buf_.size(); } //! @brief Returns true if the buffer is empty. [[nodiscard]] _CCCL_HOST_API bool empty() const noexcept { return __buf_.size() == 0; } //! @brief Returns the alignment used for the allocation. [[nodiscard]] _CCCL_HOST_API constexpr size_type alignment() const noexcept { return __buf_.alignment(); } //! @rst //! Returns a \c const reference to the :ref:`any_resource ` that holds the //! memory resource used to allocate the buffer //! @endrst [[nodiscard]] _CCCL_HOST_API const __resource_t& memory_resource() const noexcept { return __buf_.memory_resource(); } //! @brief Returns the stored stream //! @note Stream used to allocate the buffer is initially stored in the //! buffer, but can be changed with `set_stream` [[nodiscard]] _CCCL_HOST_API constexpr stream_ref stream() const noexcept { return __buf_.stream(); } //! @brief Replaces the stored stream //! @param __new_stream the new stream //! @note Always synchronizes with the old stream _CCCL_HOST_API constexpr void set_stream(stream_ref __new_stream) { __buf_.set_stream_unsynchronized(__new_stream); } //! @brief Move assignment operator //! @param __other The other buffer. After move assignment, the other buffer //! can only be assigned to or destroyed. _CCCL_HOST_API void operator=(buffer&& __other) noexcept { __buf_ = ::cuda::std::move(__other.__buf_); } //! @brief Swaps the contents of a buffer with those of \p __other //! @param __other The other buffer. _CCCL_HOST_API void swap(buffer& __other) noexcept { ::cuda::std::swap(__buf_, __other.__buf_); } //! @brief Swaps the contents of two buffers //! @param __lhs One buffer. //! @param __rhs The other buffer. _CCCL_HOST_API friend void swap(buffer& __lhs, buffer& __rhs) noexcept { __lhs.swap(__rhs); } //! @brief Destroys the buffer, deallocates the buffer and destroys the memory //! resource //! @param __stream The stream to deallocate the buffer on. //! @warning After this explicit destroy call, the buffer can only be assigned //! to or destroyed. _CCCL_HOST_API void destroy(::cuda::stream_ref __stream) noexcept { __buf_.destroy(__stream); } //! @brief Destroys the buffer, deallocates the buffer and destroys the memory //! resource //! @note Uses the stored stream to deallocate the buffer, equivalent to //! calling buffer.destroy(buffer.stream()) //! @warning After this explicit destroy call, the buffer can only be assigned //! to or destroyed. _CCCL_HOST_API void destroy() noexcept { __buf_.destroy(); } # ifndef _CCCL_DOXYGEN_INVOKED _CCCL_HOST_API constexpr void __set_size_unsynchronized(size_type __size) noexcept { __buf_.__set_size(__size); } _CCCL_HOST_API buffer __replace_allocation(::cuda::stream_ref __stream, size_type __capacity) { return buffer{__buf_.__replace_allocation(__stream, __capacity)}; } _CCCL_HOST_API void __replace_allocation_discard(::cuda::stream_ref __stream, size_type __capacity, size_type __old_capacity) { __buf_.__replace_allocation_discard(__stream, __capacity, __old_capacity); } # endif // _CCCL_DOXYGEN_INVOKED //! @brief Causes the buffer to be treated as a span when passed to //! cuda::launch. //! @pre The buffer must have the cuda::mr::device_accessible property. template [[nodiscard]] _CCCL_HOST_API friend auto transform_launch_argument(::cuda::stream_ref, buffer& __self) noexcept _CCCL_TRAILING_REQUIRES(::cuda::std::span<_Tp>)(::cuda::std::__is_included_in_v<_DeviceAccessible, _Properties...>) { return {__self.__unwrapped_begin(), __self.size()}; } //! @brief Causes the buffer to be treated as a span when passed to //! cuda::launch //! @pre The buffer must have the cuda::mr::device_accessible property. template [[nodiscard]] _CCCL_HOST_API friend auto transform_launch_argument(::cuda::stream_ref, const buffer& __self) noexcept _CCCL_TRAILING_REQUIRES(::cuda::std::span)( ::cuda::std::__is_included_in_v<_DeviceAccessible, _Properties...>) { return {__self.__unwrapped_begin(), __self.size()}; } //! @brief Forwards the passed properties _CCCL_TEMPLATE(class _Property) _CCCL_REQUIRES((!property_with_value<_Property>) _CCCL_AND ::cuda::std::__is_included_in_v<_Property, _Properties...>) _CCCL_HOST_API friend void get_property(const buffer&, _Property) noexcept {} }; _CCCL_END_NAMESPACE_ABI_VER4_BUMP template using device_buffer = buffer<_Tp, ::cuda::mr::device_accessible>; template using host_buffer = buffer<_Tp, ::cuda::mr::host_accessible>; template using __buffer_type_for_props = typename ::cuda::std::remove_reference_t<_PropsList>::template rebind; template _CCCL_HOST_API void __copy_cross_buffers( stream_ref __stream, _BufferTo& __to, const _BufferFrom& __from, typename _BufferFrom::size_type __count) { ::cuda::__ensure_current_context __guard(__stream); __stream.wait(__from.stream()); ::cuda::__driver::__memcpyAsync( __to.__unwrapped_begin(), __from.__unwrapped_begin(), sizeof(typename _BufferTo::value_type) * __count, __stream.get()); } template _CCCL_HOST_API void __copy_cross_buffers(stream_ref __stream, _BufferTo& __to, const _BufferFrom& __from) { ::cuda::__copy_cross_buffers(__stream, __to, __from, __from.size()); } _CCCL_BEGIN_NAMESPACE_ARCH_DEPENDENT //! @brief Copy-constructs elements in the range `[__first, __first + __count)`. //! @param __first Pointer to the first element to be initialized. //! @param __count The number of elements to be initialized. template _CCCL_HOST_API void __fill_n(cuda::stream_ref __stream, _Tp* __first, ::cuda::std::size_t __count, const _Tp& __value) { if (__count == 0) { return; } // We don't know what to do with both device and host accessible buffers, so // we need to check the attributes if constexpr (_Accessability == mr::__memory_accessibility ::__host_device) { __driver::__pointer_attribute_value_type_t __type; bool __is_managed{}; auto __status1 = ::cuda::__driver::__pointerGetAttributeNoThrow(__type, __first); auto __status2 = ::cuda::__driver::__pointerGetAttributeNoThrow(__is_managed, __first); if (__status1 != ::cudaSuccess || __status2 != ::cudaSuccess) { _CCCL_THROW(::cuda::cuda_error, __status1, "Failed to get buffer memory attributes"); } if (__type == ::CU_MEMORYTYPE_HOST && !__is_managed) { __fill_n<_Tp, mr::__memory_accessibility ::__host>(__stream, __first, __count, __value); } else { __fill_n<_Tp, mr::__memory_accessibility ::__device>(__stream, __first, __count, __value); } } else if constexpr (_Accessability == mr::__memory_accessibility ::__host) { ::cuda::host_launch( __stream, ::cuda::std::uninitialized_fill_n<_Tp*, ::cuda::std::size_t, _Tp>, __first, __count, __value); } else if constexpr (::cuda::__driver::__cu_driver_memsetable<_Tp>) { ::cuda::__driver::__memsetAsync(__first, __value, __count, __stream.get()); } else { # if _CCCL_CUDA_COMPILATION() ::cuda::__ensure_current_context __guard(__stream); CUB_NS_QUALIFIER::DeviceTransform::Fill(__first, __count, __value, __stream.get()); # else // ^^^ _CCCL_CUDA_COMPILATION() ^^^ / vvv !_CCCL_CUDA_COMPILATION() vvv static_assert(::cuda::__driver::__cu_driver_memsetable<_Tp>, "CUDA compiler is required to initialize an async_buffer with elements unable to be initialized " "with cuMemSet"); # endif // ^^^ !_CCCL_CUDA_COMPILATION() ^^^ } } _CCCL_END_NAMESPACE_ARCH_DEPENDENT // Require at least one explicit property on the source, so it doesn't look applicable for initializer list inputs _CCCL_TEMPLATE(class _Tp, class _FirstProperty, class... _RestProperties, class _Resource, class _FirstSourceProperty, class... _RestSourceProperties, class _Env = ::cuda::std::execution::env<>) _CCCL_REQUIRES( ::cuda::mr::synchronous_resource_with<::cuda::std::decay_t<_Resource>, _FirstProperty, _RestProperties...> _CCCL_AND __buffer_compatible_env<_Env>) _CCCL_HOST_API buffer<_Tp, _FirstProperty, _RestProperties...> make_buffer( stream_ref __stream, _Resource&& __mr, const buffer<_Tp, _FirstSourceProperty, _RestSourceProperties...>& __source, const _Env& __env = {}) { buffer<_Tp, _FirstProperty, _RestProperties...> __res{ __stream, ::cuda::std::forward<_Resource>(__mr), __source.size(), no_init, __env}; __copy_cross_buffers(__stream, __res, __source); return __res; } //! @brief Creates a buffer by copying from \p __source, using the default properties of \p __mr //! @param __stream The stream used for allocation and copy. //! @param __mr The memory resource used for allocation. //! @param __source The source buffer to copy from. //! @param __env The environment providing additional configuration. # ifdef _CCCL_DOXYGEN_INVOKED template > _CCCL_HOST_API auto make_buffer( stream_ref __stream, _Resource&& __mr, const buffer<_Tp, _FirstSourceProperty, _RestSourceProperties...>& __source, const _Env& __env = {}); # else // ^^^ _CCCL_DOXYGEN_INVOKED ^^^ / vvv !_CCCL_DOXYGEN_INVOKED vvv _CCCL_TEMPLATE(class _Tp, class _Resource, class _FirstSourceProperty, class... _RestSourceProperties, class _Env = ::cuda::std::execution::env<>) _CCCL_REQUIRES(::cuda::mr::synchronous_resource<::cuda::std::decay_t<_Resource>> _CCCL_AND ::cuda::mr::__has_default_queries<::cuda::std::decay_t<_Resource>>) _CCCL_HOST_API auto make_buffer( stream_ref __stream, _Resource&& __mr, const buffer<_Tp, _FirstSourceProperty, _RestSourceProperties...>& __source, const _Env& __env = {}) { using __buffer_type = __buffer_type_for_props<_Tp, typename ::cuda::std::decay_t<_Resource>::default_queries>; auto __res = __buffer_type{__stream, ::cuda::std::forward<_Resource>(__mr), __source.size(), no_init, __env}; __copy_cross_buffers(__stream, __res, __source); return __res; } # endif // _CCCL_DOXYGEN_INVOKED // Empty buffer make function _CCCL_TEMPLATE( class _Tp, class _FirstProperty, class... _RestProperties, class _Resource, class _Env = ::cuda::std::execution::env<>) _CCCL_REQUIRES( ::cuda::mr::synchronous_resource_with<::cuda::std::decay_t<_Resource>, _FirstProperty, _RestProperties...> _CCCL_AND __buffer_compatible_env<_Env>) buffer<_Tp, _FirstProperty, _RestProperties...> make_buffer(stream_ref __stream, _Resource&& __mr, const _Env& __env = {}) { return buffer<_Tp, _FirstProperty, _RestProperties...>{__stream, ::cuda::std::forward<_Resource>(__mr), __env}; } //! @brief Creates an empty buffer using the default properties of \p __mr //! @param __stream The stream used for allocation. //! @param __mr The memory resource used for allocation. //! @param __env The environment providing additional configuration. # ifdef _CCCL_DOXYGEN_INVOKED template > _CCCL_HOST_API auto make_buffer(stream_ref __stream, _Resource&& __mr, const _Env& __env = {}); # else // ^^^ _CCCL_DOXYGEN_INVOKED ^^^ / vvv !_CCCL_DOXYGEN_INVOKED vvv _CCCL_TEMPLATE(class _Tp, class _Resource, class _Env = ::cuda::std::execution::env<>) _CCCL_REQUIRES(::cuda::mr::synchronous_resource<::cuda::std::decay_t<_Resource>> _CCCL_AND ::cuda::mr::__has_default_queries<::cuda::std::decay_t<_Resource>> _CCCL_AND __buffer_compatible_env<_Env>) _CCCL_HOST_API auto make_buffer(stream_ref __stream, _Resource&& __mr, const _Env& __env = {}) { using __buffer_type = __buffer_type_for_props<_Tp, typename ::cuda::std::decay_t<_Resource>::default_queries>; return __buffer_type{__stream, ::cuda::std::forward<_Resource>(__mr), __env}; } # endif // _CCCL_DOXYGEN_INVOKED _CCCL_BEGIN_NAMESPACE_ARCH_DEPENDENT // Size and value make function _CCCL_TEMPLATE( class _Tp, class _FirstProperty, class... _RestProperties, class _Resource, class _Env = ::cuda::std::execution::env<>) _CCCL_REQUIRES( ::cuda::mr::synchronous_resource_with<::cuda::std::decay_t<_Resource>, _FirstProperty, _RestProperties...> _CCCL_AND __buffer_compatible_env<_Env>) _CCCL_HOST_API buffer<_Tp, _FirstProperty, _RestProperties...> make_buffer( stream_ref __stream, _Resource&& __mr, size_t __size, const _Tp& __value, [[maybe_unused]] const _Env& __env = {}) { auto __res = buffer<_Tp, _FirstProperty, _RestProperties...>{__stream, ::cuda::std::forward<_Resource>(__mr), __size, no_init}; __fill_n<_Tp, mr::__memory_accessibility_from_properties<_FirstProperty, _RestProperties...>::value>( __stream, __res.__unwrapped_begin(), __size, __value); return __res; } //! @brief Creates a buffer of \p __size elements initialized to \p __value, using the default properties of \p __mr //! @param __stream The stream used for allocation and initialization. //! @param __mr The memory resource used for allocation. //! @param __size The number of elements. //! @param __value The value to initialize elements with. //! @param __env The environment providing additional configuration. # ifdef _CCCL_DOXYGEN_INVOKED template > _CCCL_HOST_API auto make_buffer(stream_ref __stream, _Resource&& __mr, size_t __size, const _Tp& __value, const _Env& __env = {}); # else // ^^^ _CCCL_DOXYGEN_INVOKED ^^^ / vvv !_CCCL_DOXYGEN_INVOKED vvv _CCCL_TEMPLATE(class _Tp, class _Resource, class _Env = ::cuda::std::execution::env<>) _CCCL_REQUIRES(::cuda::mr::synchronous_resource<::cuda::std::decay_t<_Resource>> _CCCL_AND ::cuda::mr::__has_default_queries<::cuda::std::decay_t<_Resource>>) _CCCL_HOST_API auto make_buffer( stream_ref __stream, _Resource&& __mr, size_t __size, const _Tp& __value, [[maybe_unused]] const _Env& __env = {}) { using __default_queries = typename ::cuda::std::decay_t<_Resource>::default_queries; using __buffer_type = __buffer_type_for_props<_Tp, __default_queries>; auto __res = __buffer_type{__stream, ::cuda::std::forward<_Resource>(__mr), __size, no_init}; __fill_n<_Tp, __default_queries::template rebind::value>( __stream, __res.__unwrapped_begin(), __size, __value); return __res; } # endif // _CCCL_DOXYGEN_INVOKED _CCCL_END_NAMESPACE_ARCH_DEPENDENT // Size with no initialization make function _CCCL_TEMPLATE( class _Tp, class _FirstProperty, class... _RestProperties, class _Resource, class _Env = ::cuda::std::execution::env<>) _CCCL_REQUIRES( ::cuda::mr::synchronous_resource_with<::cuda::std::decay_t<_Resource>, _FirstProperty, _RestProperties...> _CCCL_AND __buffer_compatible_env<_Env>) buffer<_Tp, _FirstProperty, _RestProperties...> make_buffer(stream_ref __stream, _Resource&& __mr, size_t __size, ::cuda::no_init_t, const _Env& __env = {}) { return buffer<_Tp, _FirstProperty, _RestProperties...>{ __stream, ::cuda::std::forward<_Resource>(__mr), __size, ::cuda::no_init, __env}; } //! @brief Creates a buffer of \p __size uninitialized elements, using the default properties of \p __mr //! @param __stream The stream used for allocation. //! @param __mr The memory resource used for allocation. //! @param __size The number of elements. //! @param __env The environment providing additional configuration. # ifdef _CCCL_DOXYGEN_INVOKED template > _CCCL_HOST_API auto make_buffer(stream_ref __stream, _Resource&& __mr, size_t __size, ::cuda::no_init_t, const _Env& __env = {}); # else // ^^^ _CCCL_DOXYGEN_INVOKED ^^^ / vvv !_CCCL_DOXYGEN_INVOKED vvv _CCCL_TEMPLATE(class _Tp, class _Resource, class _Env = ::cuda::std::execution::env<>) _CCCL_REQUIRES(::cuda::mr::synchronous_resource<::cuda::std::decay_t<_Resource>> _CCCL_AND ::cuda::mr::__has_default_queries<_Resource>) _CCCL_HOST_API auto make_buffer(stream_ref __stream, _Resource&& __mr, size_t __size, ::cuda::no_init_t, const _Env& __env = {}) { using __buffer_type = __buffer_type_for_props<_Tp, typename ::cuda::std::decay_t<_Resource>::default_queries>; return __buffer_type{__stream, ::cuda::std::forward<_Resource>(__mr), __size, ::cuda::no_init, __env}; } # endif // _CCCL_DOXYGEN_INVOKED // Iterator range make function _CCCL_TEMPLATE(class _Tp, class _FirstProperty, class... _RestProperties, class _Resource, class _Iter, class _Env = ::cuda::std::execution::env<>) _CCCL_REQUIRES( ::cuda::mr::synchronous_resource_with<::cuda::std::decay_t<_Resource>, _FirstProperty, _RestProperties...> _CCCL_AND __buffer_compatible_env<_Env> _CCCL_AND ::cuda::std::__has_forward_traversal<_Iter>) buffer<_Tp, _FirstProperty, _RestProperties...> make_buffer(stream_ref __stream, _Resource&& __mr, _Iter __first, _Iter __last, const _Env& __env = {}) { return buffer<_Tp, _FirstProperty, _RestProperties...>{ __stream, ::cuda::std::forward<_Resource>(__mr), __first, __last, __env}; } //! @brief Creates a buffer from the iterator range `[__first, __last)`, using the default properties of \p __mr //! @param __stream The stream used for allocation and copy. //! @param __mr The memory resource used for allocation. //! @param __first The start of the input sequence. //! @param __last The end of the input sequence. //! @param __env The environment providing additional configuration. # ifdef _CCCL_DOXYGEN_INVOKED template > _CCCL_HOST_API auto make_buffer(stream_ref __stream, _Resource&& __mr, _Iter __first, _Iter __last, const _Env& __env = {}); # else // ^^^ _CCCL_DOXYGEN_INVOKED ^^^ / vvv !_CCCL_DOXYGEN_INVOKED vvv _CCCL_TEMPLATE(class _Tp, class _Resource, class _Iter, class _Env = ::cuda::std::execution::env<>) _CCCL_REQUIRES( ::cuda::mr::synchronous_resource<::cuda::std::decay_t<_Resource>> _CCCL_AND ::cuda::mr::__has_default_queries<_Resource> _CCCL_AND ::cuda::std::__has_forward_traversal<_Iter>) _CCCL_HOST_API auto make_buffer(stream_ref __stream, _Resource&& __mr, _Iter __first, _Iter __last, const _Env& __env = {}) { using __buffer_type = __buffer_type_for_props<_Tp, typename ::cuda::std::decay_t<_Resource>::default_queries>; return __buffer_type{__stream, ::cuda::std::forward<_Resource>(__mr), __first, __last, __env}; } # endif // _CCCL_DOXYGEN_INVOKED // Initializer list make function _CCCL_TEMPLATE( class _Tp, class _FirstProperty, class... _RestProperties, class _Resource, class _Env = ::cuda::std::execution::env<>) _CCCL_REQUIRES( ::cuda::mr::synchronous_resource_with<::cuda::std::decay_t<_Resource>, _FirstProperty, _RestProperties...> _CCCL_AND __buffer_compatible_env<_Env>) buffer<_Tp, _FirstProperty, _RestProperties...> make_buffer(stream_ref __stream, _Resource&& __mr, ::cuda::std::initializer_list<_Tp> __ilist, const _Env& __env = {}) { return buffer<_Tp, _FirstProperty, _RestProperties...>{ __stream, ::cuda::std::forward<_Resource>(__mr), __ilist, __env}; } //! @brief Creates a buffer from \p __ilist, using the default properties of \p __mr //! @param __stream The stream used for allocation and copy. //! @param __mr The memory resource used for allocation. //! @param __ilist The initializer_list being copied into the buffer. //! @param __env The environment providing additional configuration. # ifdef _CCCL_DOXYGEN_INVOKED template > _CCCL_HOST_API auto make_buffer(stream_ref __stream, _Resource&& __mr, ::cuda::std::initializer_list<_Tp> __ilist, const _Env& __env = {}); # else // ^^^ _CCCL_DOXYGEN_INVOKED ^^^ / vvv !_CCCL_DOXYGEN_INVOKED vvv _CCCL_TEMPLATE(class _Tp, class _Resource, class _Env = ::cuda::std::execution::env<>) _CCCL_REQUIRES(::cuda::mr::synchronous_resource<::cuda::std::decay_t<_Resource>> _CCCL_AND ::cuda::mr::__has_default_queries<::cuda::std::decay_t<_Resource>>) _CCCL_HOST_API auto make_buffer(stream_ref __stream, _Resource&& __mr, ::cuda::std::initializer_list<_Tp> __ilist, const _Env& __env = {}) { using __buffer_type = __buffer_type_for_props<_Tp, typename ::cuda::std::decay_t<_Resource>::default_queries>; return __buffer_type{__stream, ::cuda::std::forward<_Resource>(__mr), __ilist, __env}; } # endif // _CCCL_DOXYGEN_INVOKED // Range make function for ranges _CCCL_TEMPLATE(class _Tp, class _FirstProperty, class... _RestProperties, class _Resource, class _Range, class _Env = ::cuda::std::execution::env<>) _CCCL_REQUIRES( ::cuda::mr::synchronous_resource_with<::cuda::std::decay_t<_Resource>, _FirstProperty, _RestProperties...> _CCCL_AND __buffer_compatible_env<_Env> _CCCL_AND ::cuda::std::ranges::forward_range<_Range>) buffer<_Tp, _FirstProperty, _RestProperties...> make_buffer(stream_ref __stream, _Resource&& __mr, _Range&& __range, const _Env& __env = {}) { return buffer<_Tp, _FirstProperty, _RestProperties...>{ __stream, ::cuda::std::forward<_Resource>(__mr), ::cuda::std::forward<_Range>(__range), __env}; } //! @brief Creates a buffer from \p __range, using the default properties of \p __mr //! @param __stream The stream used for allocation and copy. //! @param __mr The memory resource used for allocation. //! @param __range The input range to be copied into the buffer. //! @param __env The environment providing additional configuration. # ifdef _CCCL_DOXYGEN_INVOKED template > _CCCL_HOST_API auto make_buffer(stream_ref __stream, _Resource&& __mr, _Range&& __range, const _Env& __env = {}); # else // ^^^ _CCCL_DOXYGEN_INVOKED ^^^ / vvv !_CCCL_DOXYGEN_INVOKED vvv _CCCL_TEMPLATE(class _Tp, class _Resource, class _Range, class _Env = ::cuda::std::execution::env<>) _CCCL_REQUIRES( ::cuda::mr::synchronous_resource<::cuda::std::decay_t<_Resource>> _CCCL_AND ::cuda::mr::__has_default_queries< ::cuda::std::decay_t<_Resource>> _CCCL_AND ::cuda::std::ranges::forward_range<_Range>) _CCCL_HOST_API auto make_buffer(stream_ref __stream, _Resource&& __mr, _Range&& __range, const _Env& __env = {}) { using __buffer_type = __buffer_type_for_props<_Tp, typename ::cuda::std::decay_t<_Resource>::default_queries>; return __buffer_type{__stream, ::cuda::std::forward<_Resource>(__mr), ::cuda::std::forward<_Range>(__range), __env}; } # endif // _CCCL_DOXYGEN_INVOKED _CCCL_END_NAMESPACE_CUDA # include #endif // _CCCL_HAS_CTK() #endif //_CUDA___CONTAINER_BUFFER_H