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

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

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

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

View File

@@ -0,0 +1,347 @@
//===----------------------------------------------------------------------===//
//
// 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___ITERATOR_CONSTANT_ITERATOR_H
#define _CUDA___ITERATOR_CONSTANT_ITERATOR_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/__fwd/iterator.h>
#include <cuda/std/__concepts/constructible.h>
#include <cuda/std/__iterator/concepts.h>
#include <cuda/std/__iterator/iterator_traits.h>
#include <cuda/std/__ranges/compressed_movable_box.h>
#include <cuda/std/__type_traits/is_integral.h>
#include <cuda/std/__type_traits/is_nothrow_copy_constructible.h>
#include <cuda/std/__type_traits/is_nothrow_default_constructible.h>
#include <cuda/std/__type_traits/is_nothrow_move_constructible.h>
#include <cuda/std/__type_traits/is_signed.h>
#include <cuda/std/__utility/move.h>
#include <cuda/std/__cccl/prologue.h>
_CCCL_BEGIN_NAMESPACE_CUDA
//! @addtogroup iterators
//! @{
//! @brief The @c constant_iterator class represents an iterator in an infinite sequence of repeated values.
//! @tparam _Tp the value type of the @c constant_iterator.
//! @tparam _Index The index type of the @c constant_iterator. It can optionally be specified, but must satisfy
//! __integer-like__
//!
//! This iterator is useful for creating a range filled with the same value without explicitly storing it in memory.
//! Using @c constant_iterator saves both memory capacity and bandwidth.
//!
//! The following code snippet demonstrates how to create a @c constant_iterator whose @c value_type is @c int and whose
//! value is @c 10.
//!
//! @code{.cpp}
//! #include <cuda/iterator>
//!
//! cuda::constant_iterator iter(10);
//!
//! *iter; // returns 10
//! iter[0]; // returns 10
//! iter[1]; // returns 10
//! iter[13]; // returns 10
//!
//! // and so on...
//! @endcode
template <class _Tp, class _Index>
class constant_iterator
{
private:
static_assert(::cuda::std::__integer_like<_Index>, "The index type of cuda::constant_iterator must be integer-like!");
// Not a base because then the friend operators would be ambiguous
::cuda::std::__compressed_movable_box<_Index, _Tp> __store_;
[[nodiscard]] _CCCL_API constexpr _Index& __index() noexcept
{
return __store_.template __get<0>();
}
[[nodiscard]] _CCCL_API constexpr const _Index& __index() const noexcept
{
return __store_.template __get<0>();
}
[[nodiscard]] _CCCL_API constexpr _Tp& __value() noexcept
{
return __store_.template __get<1>();
}
[[nodiscard]] _CCCL_API constexpr const _Tp& __value() const noexcept
{
return __store_.template __get<1>();
}
public:
using iterator_concept = ::cuda::std::random_access_iterator_tag;
using iterator_category = ::cuda::std::random_access_iterator_tag;
using value_type = _Tp;
using difference_type = ::cuda::std::ptrdiff_t;
// Those are technically not to spec, but pre-ranges iterator_traits do not work properly with iterators that do not
// define all 5 aliases, see https://en.cppreference.com/w/cpp/iterator/iterator_traits.html
using reference = _Tp;
using pointer = void;
_CCCL_EXEC_CHECK_DISABLE
_CCCL_TEMPLATE(class _Tp2 = _Tp)
_CCCL_REQUIRES(::cuda::std::default_initializable<_Tp2>)
_CCCL_API constexpr constant_iterator() noexcept(::cuda::std::is_nothrow_default_constructible_v<_Tp2>)
: __store_()
{}
//! @brief Creates a @c constant_iterator from a value. The index is set to zero
//! @param __value The value to store in the @c constant_iterator
_CCCL_EXEC_CHECK_DISABLE
_CCCL_API constexpr constant_iterator(_Tp __value) noexcept(::cuda::std::is_nothrow_move_constructible_v<_Tp>)
: __store_(0, ::cuda::std::move(__value))
{}
//! @brief Creates @c constant_iterator from a value and an index
//! @param __value The value to store in the @c constant_iterator
//! @param __index The index in the sequence represented by this @c constant_iterator
_CCCL_EXEC_CHECK_DISABLE
_CCCL_TEMPLATE(typename _Index2)
_CCCL_REQUIRES(::cuda::std::__integer_like<_Index2>)
_CCCL_API constexpr explicit constant_iterator(_Tp __value, _Index2 __index) noexcept(
::cuda::std::is_nothrow_move_constructible_v<_Tp>)
: __store_(static_cast<_Index>(__index), ::cuda::std::move(__value))
{}
//! @brief Returns a the current index
[[nodiscard]] _CCCL_API constexpr difference_type index() const noexcept
{
return static_cast<difference_type>(__index());
}
_CCCL_EXEC_CHECK_DISABLE
//! @brief Returns the stored value
[[nodiscard]] _CCCL_API constexpr reference operator*() const noexcept
{
return __value();
}
_CCCL_EXEC_CHECK_DISABLE
//! @brief Returns the stored value
[[nodiscard]] _CCCL_API constexpr reference operator[](difference_type) const noexcept
{
return __value();
}
//! @brief Increments the stored index
_CCCL_EXEC_CHECK_DISABLE
_CCCL_API constexpr constant_iterator& operator++() noexcept
{
++__index();
return *this;
}
//! @brief Increments the stored index
_CCCL_EXEC_CHECK_DISABLE
_CCCL_API constexpr constant_iterator operator++(int) noexcept(::cuda::std::is_nothrow_copy_constructible_v<_Tp>)
{
auto __tmp = *this;
++__index();
return __tmp;
}
//! @brief Decrements the stored index
_CCCL_EXEC_CHECK_DISABLE
_CCCL_API constexpr constant_iterator& operator--() noexcept
{
if constexpr (::cuda::std::is_signed_v<_Index> || !::cuda::std::is_integral_v<_Index>)
{
_CCCL_ASSERT(__index() > 0, "The index must be greater than or equal to 0");
}
--__index();
return *this;
}
//! @brief Decrements the stored index
_CCCL_EXEC_CHECK_DISABLE
_CCCL_API constexpr constant_iterator operator--(int) noexcept(::cuda::std::is_nothrow_copy_constructible_v<_Tp>)
{
if constexpr (::cuda::std::is_signed_v<_Index> || !::cuda::std::is_integral_v<_Index>)
{
_CCCL_ASSERT(__index() > 0, "The index must be greater than or equal to 0");
}
auto __tmp = *this;
--__index();
return __tmp;
}
//! @brief Advances a @c constant_iterator by a given number of elements
//! @param __n The amount of elements to advance
_CCCL_EXEC_CHECK_DISABLE
_CCCL_API constexpr constant_iterator& operator+=(difference_type __n) noexcept
{
if constexpr (::cuda::std::is_signed_v<_Index> || !::cuda::std::is_integral_v<_Index>)
{
_CCCL_ASSERT(__index() + __n >= 0, "The index must be greater than or equal to 0");
}
__index() += static_cast<_Index>(__n);
return *this;
}
//! @brief Creates a copy of a @c constant_iterator advanced by a given number of elements
//! @param __iter The @c constant_iterator to advance
//! @param __n The amount of elements to advance
_CCCL_EXEC_CHECK_DISABLE
template <int = 0> // Must be template, or the compiler complains about a nonliteral return type
[[nodiscard]] _CCCL_API friend constexpr constant_iterator operator+(
const constant_iterator& __iter, difference_type __n) noexcept(::cuda::std::is_nothrow_copy_constructible_v<_Tp>)
{
if constexpr (::cuda::std::is_signed_v<_Index>)
{
_CCCL_ASSERT(__iter.__index() + __n >= 0, "The index must be greater than or equal to 0");
}
return constant_iterator{__iter.__value(), __iter.__index() + __n};
}
//! @brief Creates a copy of a @c constant_iterator advanced by a given number of elements
//! @param __n The amount of elements to advance
//! @param __iter The @c constant_iterator to advance
_CCCL_EXEC_CHECK_DISABLE
template <int = 0> // Must be template, or the compiler complains about a nonliteral return type
[[nodiscard]] _CCCL_API friend constexpr constant_iterator operator+(
difference_type __n, const constant_iterator& __iter) noexcept(::cuda::std::is_nothrow_copy_constructible_v<_Tp>)
{
if constexpr (::cuda::std::is_signed_v<_Index>)
{
_CCCL_ASSERT(__iter.__index() + __n >= 0, "The index must be greater than or equal to 0");
}
return constant_iterator{__iter.__value(), __iter.__index() + __n};
}
//! @brief Decrements a @c constant_iterator by a given number of elements
//! @param __n The amount of elements to decrement
_CCCL_EXEC_CHECK_DISABLE
_CCCL_API constexpr constant_iterator& operator-=(difference_type __n) noexcept
{
if constexpr (::cuda::std::is_signed_v<_Index>)
{
_CCCL_ASSERT(__index() - __n >= 0, "The index must be greater than or equal to 0");
}
__index() -= static_cast<_Index>(__n);
return *this;
}
//! @brief Creates a copy of a @c constant_iterator decremented by a given number of elements
//! @param __n The amount of elements to decrement
//! @param __iter The @c constant_iterator to decrement
_CCCL_EXEC_CHECK_DISABLE
template <int = 0> // Must be template, or the compiler complains about a nonliteral return type
[[nodiscard]] _CCCL_API friend constexpr constant_iterator operator-(
const constant_iterator& __iter, difference_type __n) noexcept(::cuda::std::is_nothrow_copy_constructible_v<_Tp>)
{
if constexpr (::cuda::std::is_signed_v<_Index>)
{
_CCCL_ASSERT(__iter.__index() - __n >= 0, "The index must be greater than or equal to 0");
}
return constant_iterator{__iter.__value(), __iter.__index() - __n};
}
//! @brief Returns the distance between two @c constant_iterator
[[nodiscard]] _CCCL_API friend constexpr difference_type
operator-(const constant_iterator& __lhs, const constant_iterator& __rhs) noexcept
{
return static_cast<difference_type>(__lhs.__index()) - static_cast<difference_type>(__rhs.__index());
}
//! @brief Compares two @c constant_iterator for equality by comparing the index in the sequence
[[nodiscard]] _CCCL_API friend constexpr bool
operator==(const constant_iterator& __lhs, const constant_iterator& __rhs) noexcept
{
return __lhs.__index() == __rhs.__index();
}
#if _CCCL_STD_VER <= 2017
//! @brief Compares two @c constant_iterator for inequality by comparing the index in the sequence
[[nodiscard]] _CCCL_API friend constexpr bool
operator!=(const constant_iterator& __lhs, const constant_iterator& __rhs) noexcept
{
return __lhs.__index() != __rhs.__index();
}
#endif // _CCCL_STD_VER <= 2017
#if _LIBCUDACXX_HAS_SPACESHIP_OPERATOR()
//! @brief Three-way-compares two @c constant_iterator by comparing the index in the sequence
[[nodiscard]] _CCCL_API friend constexpr auto
operator<=>(const constant_iterator& __lhs, const constant_iterator& __rhs) noexcept
{
return __lhs.__index() <=> __rhs.__index();
}
#else // ^^^ _LIBCUDACXX_HAS_SPACESHIP_OPERATOR() ^^^ / vvv !_LIBCUDACXX_HAS_SPACESHIP_OPERATOR() vvv
//! @brief Compares two @c constant_iterator for less than by comparing the index in the sequence
[[nodiscard]] _CCCL_API friend constexpr bool
operator<(const constant_iterator& __lhs, const constant_iterator& __rhs) noexcept
{
return __lhs.__index() < __rhs.__index();
}
//! @brief Compares two @c constant_iterator for less equal by comparing the index in the sequence
[[nodiscard]] _CCCL_API friend constexpr bool
operator<=(const constant_iterator& __lhs, const constant_iterator& __rhs) noexcept
{
return __lhs.__index() <= __rhs.__index();
}
//! @brief Compares two @c constant_iterator for greater than by comparing the index in the sequence
[[nodiscard]] _CCCL_API friend constexpr bool
operator>(const constant_iterator& __lhs, const constant_iterator& __rhs) noexcept
{
return __lhs.__index() > __rhs.__index();
}
//! @brief Compares two @c constant_iterator for greater equal by comparing the index in the sequence
[[nodiscard]] _CCCL_API friend constexpr bool
operator>=(const constant_iterator& __lhs, const constant_iterator& __rhs) noexcept
{
return __lhs.__index() >= __rhs.__index();
}
#endif // !_LIBCUDACXX_HAS_NO_SPACESHIP_OPERATOR()
};
#ifndef _CCCL_DOXYGEN_INVOKED
template <class _Tp>
_CCCL_DEDUCTION_GUIDE_ATTRIBUTES constant_iterator(_Tp) -> constant_iterator<_Tp, ::cuda::std::ptrdiff_t>;
_CCCL_TEMPLATE(class _Tp, typename _Index)
_CCCL_REQUIRES(::cuda::std::__integer_like<_Index>)
_CCCL_DEDUCTION_GUIDE_ATTRIBUTES constant_iterator(_Tp, _Index) -> constant_iterator<_Tp, _Index>;
#endif // _CCCL_DOXYGEN_INVOKED
//! @brief Creates a @c constant_iterator from a value and an index
//! @param __value The value to be stored
//! @param __index The optional index representing the position in a sequence. Defaults to 0.
//! @relates constant_iterator
template <class _Tp, class _Index = ::cuda::std::ptrdiff_t>
[[nodiscard]] _CCCL_API constexpr auto make_constant_iterator(_Tp __value, _Index __index = 0)
{
return constant_iterator<_Tp, _Index>{::cuda::std::move(__value), __index};
}
//! @} // end iterators
_CCCL_END_NAMESPACE_CUDA
#include <cuda/std/__cccl/epilogue.h>
#endif // _CUDA___ITERATOR_CONSTANT_ITERATOR_H

View File

@@ -0,0 +1,552 @@
//===----------------------------------------------------------------------===//
//
// 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___ITERATOR_COUNTING_ITERATOR_H
#define _CUDA___ITERATOR_COUNTING_ITERATOR_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/__fwd/iterator.h>
#if _LIBCUDACXX_HAS_SPACESHIP_OPERATOR()
# include <cuda/std/__compare/three_way_comparable.h>
#endif // _LIBCUDACXX_HAS_SPACESHIP_OPERATOR()
#include <cuda/std/__concepts/arithmetic.h>
#include <cuda/std/__concepts/constructible.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/invocable.h>
#include <cuda/std/__concepts/same_as.h>
#include <cuda/std/__concepts/semiregular.h>
#include <cuda/std/__concepts/totally_ordered.h>
#include <cuda/std/__functional/ranges_operations.h>
#include <cuda/std/__iterator/advance.h>
#include <cuda/std/__iterator/concepts.h>
#include <cuda/std/__iterator/distance.h>
#include <cuda/std/__iterator/incrementable_traits.h>
#include <cuda/std/__iterator/iterator_traits.h>
#include <cuda/std/__iterator/unreachable_sentinel.h>
#include <cuda/std/__ranges/enable_borrowed_range.h>
#include <cuda/std/__ranges/movable_box.h>
#include <cuda/std/__ranges/view_interface.h>
#include <cuda/std/__type_traits/always_false.h>
#include <cuda/std/__type_traits/conditional.h>
#include <cuda/std/__type_traits/enable_if.h>
#include <cuda/std/__type_traits/is_comparable.h>
#include <cuda/std/__type_traits/is_constructible.h>
#include <cuda/std/__type_traits/is_nothrow_copy_constructible.h>
#include <cuda/std/__type_traits/is_nothrow_move_constructible.h>
#include <cuda/std/__type_traits/make_unsigned.h>
#include <cuda/std/__type_traits/remove_cvref.h>
#include <cuda/std/__type_traits/type_identity.h>
#include <cuda/std/__type_traits/void_t.h>
#include <cuda/std/__utility/forward.h>
#include <cuda/std/__utility/move.h>
#include <cuda/std/__cccl/prologue.h>
_CCCL_BEGIN_NAMESPACE_CUDA
//! @addtogroup iterators
//! @{
//! @cond
template <class _Iter>
_CCCL_CONCEPT __decrementable = _CCCL_REQUIRES_EXPR((_Iter), _Iter __iter)(
requires(::cuda::std::incrementable<_Iter>), _Same_as(_Iter&)(--__iter), _Same_as(_Iter)(__iter--));
template <class _Iter>
_CCCL_CONCEPT __advanceable = _CCCL_REQUIRES_EXPR((_Iter), _Iter __iter, const _Iter __j, const _IotaDiffT<_Iter> __n)(
requires(__decrementable<_Iter>),
requires(::cuda::std::totally_ordered<_Iter>),
_Same_as(_Iter&) __iter += __n,
_Same_as(_Iter&) __iter -= __n,
requires(::cuda::std::is_constructible_v<_Iter, decltype(__j + __n)>),
requires(::cuda::std::is_constructible_v<_Iter, decltype(__n + __j)>),
requires(::cuda::std::is_constructible_v<_Iter, decltype(__j - __n)>),
requires(::cuda::std::convertible_to<decltype(__j - __j), _IotaDiffT<_Iter>>));
template <class, class = void>
struct __counting_iterator_category
{};
template <class _Tp>
struct __counting_iterator_category<_Tp, ::cuda::std::enable_if_t<::cuda::std::incrementable<_Tp>>>
{
using iterator_category = ::cuda::std::input_iterator_tag;
};
//! @endcond
//! @brief A @c counting_iterator represents an iterator into a range of sequentially increasing values.
//! @tparam _Start the value type of the @c counting_iterator.
//!
//! This iterator is useful for creating a range filled with a sequence without explicitly storing it in memory. Using
//! @c counting_iterator saves memory capacity and bandwidth.
//!
//! The following code snippet demonstrates how to create a @c counting_iterator whose @c value_type is @c int
//!
//! @code{.cpp}
//! #include <cuda/iterator>
//! ...
//! // create iterators
//! cuda::counting_iterator first(10);
//! cuda::counting_iterator last = first + 3;
//!
//! first[0] // returns 10
//! first[1] // returns 11
//! first[100] // returns 110
//!
//! // sum of [first, last)
//! std::reduce(first, last); // returns 33 (i.e. 10 + 11 + 12)
//!
//! // initialize vector to [0,1,2,..]
//! cuda::counting_iterator iter(0);
//! std::vector<int> vec(500);
//! std::copy(iter, iter + vec.size(), vec.begin());
//! @endcode
#if _CCCL_HAS_CONCEPTS()
template <::cuda::std::weakly_incrementable _Start, ::cuda::std::signed_integral _DiffT>
requires ::cuda::std::copyable<_Start>
#else // ^^^ _CCCL_HAS_CONCEPTS() ^^^ / vvv !_CCCL_HAS_CONCEPTS() vvv
template <class _Start,
class _DiffT,
::cuda::std::enable_if_t<::cuda::std::weakly_incrementable<_Start>, int>,
::cuda::std::enable_if_t<::cuda::std::copyable<_Start>, int>,
::cuda::std::enable_if_t<::cuda::std::signed_integral<_DiffT>, int>>
#endif // ^^^ !_CCCL_HAS_CONCEPTS() ^^^
class counting_iterator : public __counting_iterator_category<_Start>
{
private:
_Start __value_ = _Start();
public:
using iterator_concept = ::cuda::std::conditional_t<
__advanceable<_Start>,
::cuda::std::random_access_iterator_tag,
::cuda::std::conditional_t<__decrementable<_Start>,
::cuda::std::bidirectional_iterator_tag,
::cuda::std::conditional_t<::cuda::std::incrementable<_Start>,
::cuda::std::forward_iterator_tag,
/*Else*/ ::cuda::std::input_iterator_tag>>>;
using value_type = _Start;
using difference_type = _DiffT;
// Those are technically not to spec, but pre-ranges iterator_traits do not work properly with iterators that do not
// define all 5 aliases, see https://en.cppreference.com/w/cpp/iterator/iterator_traits.html
using reference = _Start;
using pointer = void;
// Needed for comparison operators and constructors, because the other side might have a
// different difference type so we cannot reach into their private members. Usually you solve
// this with the power of friendship, but since this class uses concepts or SFINAE, spelling
// out the friendship is a faff.
//
// We also cannot use operator*() here to get the value because that imposes the additional
// burden of requiring _Start to be copy-constructible which is not needed for comparisons.
[[nodiscard]] _CCCL_API constexpr const _Start& __get_value() const noexcept
{
return __value_;
}
[[nodiscard]] _CCCL_API constexpr _Start& __get_value() noexcept
{
return __value_;
}
#if _CCCL_HAS_CONCEPTS()
_CCCL_HIDE_FROM_ABI counting_iterator()
requires ::cuda::std::default_initializable<_Start>
= default;
#else // ^^^ _CCCL_HAS_CONCEPTS() ^^^ / vvv !_CCCL_HAS_CONCEPTS() vvv
_CCCL_TEMPLATE(class _Start2 = _Start)
_CCCL_REQUIRES(::cuda::std::default_initializable<_Start2>)
_CCCL_API constexpr counting_iterator() noexcept(::cuda::std::is_nothrow_default_constructible_v<_Start2>) {}
#endif // ^^^ !_CCCL_HAS_CONCEPTS() ^^^
//! @brief Creates a @c counting_iterator from an initial value.
//! @param __value The value to store in the @c counting_iterator
_CCCL_API constexpr explicit counting_iterator(_Start __value) noexcept(
::cuda::std::is_nothrow_move_constructible_v<_Start>)
: __value_(::cuda::std::move(__value))
{}
constexpr counting_iterator(const counting_iterator&) = default;
constexpr counting_iterator(counting_iterator&&) = default;
constexpr counting_iterator& operator=(const counting_iterator&) = default;
constexpr counting_iterator& operator=(counting_iterator&&) = default;
//! @brief Creates a @c counting_iterator from another @c counting_iterator of a different
//! difference type.
//! @param __other The @c counting_iterator to copy from.
_CCCL_TEMPLATE(class _DiffT2)
_CCCL_REQUIRES((!::cuda::std::same_as<_DiffT, _DiffT2>) )
_CCCL_API constexpr explicit counting_iterator(const counting_iterator<_Start, _DiffT2>& __other) noexcept(
::cuda::std::is_nothrow_copy_constructible_v<_Start>)
: __value_(__other.__get_value())
{}
//! @brief Creates a @c counting_iterator from another @c counting_iterator of a different
//! difference type.
//! @param __other The @c counting_iterator to move from.
_CCCL_TEMPLATE(class _DiffT2)
_CCCL_REQUIRES((!::cuda::std::same_as<_DiffT, _DiffT2>) )
_CCCL_API constexpr explicit counting_iterator(counting_iterator<_Start, _DiffT2>&& __other) noexcept(
::cuda::std::is_nothrow_move_constructible_v<_Start>)
: __value_(::cuda::std::move(__other.__get_value()))
{}
//! @brief Assignment between counting iterators of differing difference types is explicitly
//! deleted. If such a conversion is intended, use the copy or move constructors to convert.
_CCCL_TEMPLATE(class _DiffT2)
_CCCL_REQUIRES((!::cuda::std::same_as<_DiffT, _DiffT2>) )
_CCCL_API constexpr counting_iterator& operator=(const counting_iterator<_Start, _DiffT2>&) = delete;
//! @brief Assignment between counting iterators of differing difference types is explicitly
//! deleted. If such a conversion is intended, use the copy or move constructors
_CCCL_TEMPLATE(class _DiffT2)
_CCCL_REQUIRES((!::cuda::std::same_as<_DiffT, _DiffT2>) )
_CCCL_API constexpr counting_iterator& operator=(counting_iterator<_Start, _DiffT2>&&) = delete;
//! @brief Returns the value currently stored in the @c counting_iterator
[[nodiscard]] _CCCL_API constexpr _Start operator*() const
noexcept(::cuda::std::is_nothrow_copy_constructible_v<_Start>)
{
return __value_;
}
//! @brief Returns the value currently stored in the @c counting_iterator advanced by a number of steps
//! @param __n The amount of elements to advance
_CCCL_TEMPLATE(class _Start2 = _Start)
_CCCL_REQUIRES(__advanceable<_Start2>)
[[nodiscard]] _CCCL_API constexpr _Start2 operator[](difference_type __n) const
noexcept(::cuda::std::is_nothrow_copy_constructible_v<_Start2>
&& noexcept(::cuda::std::declval<const _Start2&>() + __n))
{
if constexpr (::cuda::std::__integer_like<_Start>)
{
return _Start(__value_ + static_cast<_Start>(__n));
}
else
{
return _Start(__value_ + __n);
}
}
//! @brief Increments the stored value
_CCCL_API constexpr counting_iterator& operator++() noexcept(noexcept(++::cuda::std::declval<_Start&>()))
{
++__value_;
return *this;
}
//! @brief Increments the stored value
_CCCL_API constexpr auto operator++(int) noexcept(
noexcept(++::cuda::std::declval<_Start&>()) && ::cuda::std::is_nothrow_copy_constructible_v<_Start>)
{
if constexpr (::cuda::std::incrementable<_Start>)
{
auto __tmp = *this;
++__value_;
return __tmp;
}
else
{
++__value_;
}
}
//! @brief Decrements the stored value
_CCCL_TEMPLATE(class _Start2 = _Start)
_CCCL_REQUIRES(__decrementable<_Start2>)
_CCCL_API constexpr counting_iterator& operator--() noexcept(noexcept(--::cuda::std::declval<_Start2&>()))
{
--__value_;
return *this;
}
//! @brief Decrements the stored value
_CCCL_TEMPLATE(class _Start2 = _Start)
_CCCL_REQUIRES(__decrementable<_Start2>)
_CCCL_API constexpr counting_iterator operator--(int) noexcept(
noexcept(--::cuda::std::declval<_Start2&>()) && ::cuda::std::is_nothrow_copy_constructible_v<_Start>)
{
auto __tmp = *this;
--*this;
return __tmp;
}
//! @brief Increments the stored value by a given number of elements
//! @param __n The number of elements to increment
_CCCL_API constexpr counting_iterator& operator+=(difference_type __n) noexcept(::cuda::std::__integer_like<_Start>)
{
if constexpr (::cuda::std::__integer_like<_Start> && !::cuda::std::__signed_integer_like<_Start>)
{
if (__n >= difference_type(0))
{
__value_ += static_cast<_Start>(__n);
}
else
{
__value_ -= static_cast<_Start>(-__n);
}
}
else if constexpr (::cuda::std::__signed_integer_like<_Start>)
{
__value_ += static_cast<_Start>(__n);
}
else
{
__value_ += __n;
}
return *this;
}
//! @brief Creates a copy of a @c counting_iterator advanced by a given number of elements
//! @param __iter The @c counting_iterator to advance
//! @param __n The amount of elements to advance
_CCCL_TEMPLATE(class _Start2 = _Start)
_CCCL_REQUIRES(__advanceable<_Start2>)
[[nodiscard]] _CCCL_API friend constexpr counting_iterator
operator+(counting_iterator __iter, difference_type __n) noexcept(::cuda::std::__integer_like<_Start2>)
{
__iter += __n;
return __iter;
}
//! @brief Creates a copy of a @c counting_iterator advanced by a given number of elements
//! @param __iter The @c counting_iterator to advance
//! @param __n The amount of elements to advance
_CCCL_TEMPLATE(class _Start2 = _Start)
_CCCL_REQUIRES(__advanceable<_Start2>)
[[nodiscard]] _CCCL_API friend constexpr counting_iterator
operator+(difference_type __n, counting_iterator __iter) noexcept(::cuda::std::__integer_like<_Start2>)
{
return __iter + __n;
}
//! @brief Decrements the stored value by a given number of elements
//! @param __n The amount of elements to decrement
_CCCL_TEMPLATE(class _Start2 = _Start)
_CCCL_REQUIRES(__advanceable<_Start2>)
_CCCL_API constexpr counting_iterator& operator-=(difference_type __n) noexcept(::cuda::std::__integer_like<_Start2>)
{
if constexpr (::cuda::std::__integer_like<_Start> && !::cuda::std::__signed_integer_like<_Start>)
{
if (__n >= difference_type(0))
{
__value_ -= static_cast<_Start>(__n);
}
else
{
__value_ += static_cast<_Start>(-__n);
}
}
else if constexpr (::cuda::std::__signed_integer_like<_Start>)
{
__value_ -= static_cast<_Start>(__n);
}
else
{
__value_ -= __n;
}
return *this;
}
//! @brief Creates a copy of a @c counting_iterator decremented by a given number of elements
//! @param __iter The @c counting_iterator to decrement
//! @param __n The amount of elements to decrement
_CCCL_TEMPLATE(class _Start2 = _Start)
_CCCL_REQUIRES(__advanceable<_Start2>)
[[nodiscard]] _CCCL_API friend constexpr counting_iterator
operator-(counting_iterator __iter, difference_type __n) noexcept(::cuda::std::__integer_like<_Start2>)
{
__iter -= __n;
return __iter;
}
//! @brief Returns the distance between two @c counting_iterator
//! @return The difference between the stored values
_CCCL_TEMPLATE(class _Start2 = _Start)
_CCCL_REQUIRES(__advanceable<_Start2>)
[[nodiscard]] _CCCL_API friend constexpr difference_type
operator-(const counting_iterator& __x, const counting_iterator& __y) noexcept(::cuda::std::__integer_like<_Start2>)
{
if constexpr (::cuda::std::__integer_like<_Start> && !::cuda::std::__signed_integer_like<_Start>)
{
if (__y.__value_ > __x.__value_)
{
return static_cast<difference_type>(-static_cast<difference_type>(__y.__value_ - __x.__value_));
}
return static_cast<difference_type>(__x.__value_ - __y.__value_);
}
else if constexpr (::cuda::std::__signed_integer_like<_Start>)
{
return static_cast<difference_type>(
static_cast<difference_type>(__x.__value_) - static_cast<difference_type>(__y.__value_));
}
else
{
return __x.__value_ - __y.__value_;
}
}
_CCCL_TEMPLATE(class _Start2, class _DiffT2)
_CCCL_REQUIRES(::cuda::std::equality_comparable_with<_Start, _Start2>)
[[nodiscard]] _CCCL_API friend constexpr bool
operator==(const counting_iterator& __x, const counting_iterator<_Start2, _DiffT2>& __y) noexcept(
noexcept(::cuda::std::__is_cpp17_nothrow_equality_comparable_v<_Start, _Start2>))
{
return __x.__value_ == __y.__get_value();
}
#if _CCCL_STD_VER <= 2017
//! @brief Compares two @c counting_iterator for inequality.
//! @return True if the stored values do not compare equal
_CCCL_TEMPLATE(class _Start2, class _DiffT2)
_CCCL_REQUIRES(::cuda::std::equality_comparable_with<_Start, _Start2>)
[[nodiscard]] _CCCL_API friend constexpr bool
operator!=(const counting_iterator& __x, const counting_iterator<_Start2, _DiffT2>& __y) noexcept(
noexcept(::cuda::std::declval<const _Start&>() != ::cuda::std::declval<const _Start2&>()))
{
return __x.__value_ != __y.__get_value();
}
#endif // _CCCL_STD_VER <= 2017
#if _LIBCUDACXX_HAS_SPACESHIP_OPERATOR()
//! @brief Three-way compares two @c counting_iterator.
//! @return The three-way comparison of the stored values
template <class _Start2, class _DiffT2>
[[nodiscard]] _CCCL_API friend constexpr auto
operator<=>(const counting_iterator& __x, const counting_iterator<_Start2, _DiffT2>& __y) noexcept(
noexcept(::cuda::std::declval<const _Start&>() <=> ::cuda::std::declval<const _Start2&>()))
requires ::cuda::std::totally_ordered_with<_Start, _Start2>
&& ::cuda::std::three_way_comparable_with<_Start, _Start2>
{
return __x.__value_ <=> __y.__get_value();
}
#else // ^^^ _LIBCUDACXX_HAS_SPACESHIP_OPERATOR() ^^^ / vvv !_LIBCUDACXX_HAS_SPACESHIP_OPERATOR() vvv
//! @brief Compares two @c counting_iterator for less than.
//! @return True if stored values compare less than
_CCCL_TEMPLATE(class _Start2, class _DiffT2)
_CCCL_REQUIRES(::cuda::std::totally_ordered_with<_Start, _Start2>)
[[nodiscard]] _CCCL_API friend constexpr bool
operator<(const counting_iterator& __x, const counting_iterator<_Start2, _DiffT2>& __y) noexcept(
noexcept(::cuda::std::__is_cpp17_nothrow_less_than_comparable_v<_Start, _Start2>))
{
return __x.__value_ < __y.__get_value();
}
//! @brief Compares two @c counting_iterator for greater than.
//! @return True if stored values compare greater than
_CCCL_TEMPLATE(class _Start2, class _DiffT2)
_CCCL_REQUIRES(::cuda::std::totally_ordered_with<_Start, _Start2>)
[[nodiscard]] _CCCL_API friend constexpr bool
operator>(const counting_iterator& __x, const counting_iterator<_Start2, _DiffT2>& __y) noexcept(
::cuda::std::__is_cpp17_nothrow_less_than_comparable_v<_Start2, _Start>)
{
return __y < __x;
}
//! @brief Compares two @c counting_iterator for less equal.
//! @return True if stored values compare less equal
_CCCL_TEMPLATE(class _Start2, class _DiffT2)
_CCCL_REQUIRES(::cuda::std::totally_ordered_with<_Start, _Start2>)
[[nodiscard]] _CCCL_API friend constexpr bool
operator<=(const counting_iterator& __x, const counting_iterator<_Start2, _DiffT2>& __y) noexcept(
::cuda::std::__is_cpp17_nothrow_less_than_comparable_v<_Start2, _Start>)
{
return !(__y < __x);
}
//! @brief Compares two @c counting_iterator for greater equal.
//! @return True if stored values compare greater equal
_CCCL_TEMPLATE(class _Start2, class _DiffT2)
_CCCL_REQUIRES(::cuda::std::totally_ordered_with<_Start, _Start2>)
[[nodiscard]] _CCCL_API friend constexpr bool
operator>=(const counting_iterator& __x, const counting_iterator<_Start2, _DiffT2>& __y) noexcept(
::cuda::std::__is_cpp17_nothrow_less_than_comparable_v<_Start, _Start2>)
{
return !(__x < __y);
}
#endif // !_LIBCUDACXX_HAS_SPACESHIP_OPERATOR()
};
//! @brief Creates a @c counting_iterator from an __integer-like__ @c _Start
//! @param __start The __integer-like__ @c _Start representing the initial count
//! @relates counting_iterator
template <class _Start>
[[nodiscard]] _CCCL_API constexpr auto make_counting_iterator(_Start __start)
{
return counting_iterator<_Start>{__start};
}
//! @} iterators
_CCCL_END_NAMESPACE_CUDA
#ifndef _CCCL_DOXYGEN_INVOKED
# if _CCCL_HAS_HOST_STD_LIB()
_CCCL_BEGIN_NAMESPACE_STD
//! counting_iterator is a C++20 iterator, so it does not play well with legacy STL features like std::distance
//! To work around that specialize those functions for counting_iterator
template <class _Diff, class _Start, class _DiffT2>
_CCCL_HOST_API constexpr void
advance(::cuda::counting_iterator<_Start, _DiffT2>& __iter, _Diff __diff) noexcept(::cuda::std::__integer_like<_Start>)
{
::cuda::std::advance(__iter, ::cuda::std::move(__diff));
}
template <class _Start, class _DiffT>
[[nodiscard]] _CCCL_HOST_API constexpr typename ::cuda::counting_iterator<_Start, _DiffT>::difference_type
distance(::cuda::counting_iterator<_Start, _DiffT> __first,
::cuda::counting_iterator<_Start, _DiffT> __last) noexcept(::cuda::std::__integer_like<_Start>)
{
return ::cuda::std::distance(::cuda::std::move(__first), ::cuda::std::move(__last));
}
template <class _Start, class _DiffT>
[[nodiscard]] _CCCL_HOST_API constexpr ::cuda::counting_iterator<_Start, _DiffT>
next(::cuda::counting_iterator<_Start, _DiffT> __iter,
::cuda::std::type_identity_t<_DiffT> __n = 1) noexcept(::cuda::std::__integer_like<_Start>)
{
_CCCL_ASSERT(__n >= 0 || ::cuda::__decrementable<_Start>,
"Attempt to std::next(it, n) with negative n on a non-bidirectional iterator");
::cuda::std::advance(__iter, __n);
return __iter;
}
template <class _Start, class _DiffT>
[[nodiscard]] _CCCL_HOST_API constexpr ::cuda::counting_iterator<_Start, _DiffT>
prev(::cuda::counting_iterator<_Start, _DiffT> __iter,
::cuda::std::type_identity_t<_DiffT> __n = 1) noexcept(::cuda::std::__integer_like<_Start>)
{
_CCCL_ASSERT(__n >= 0 || ::cuda::__decrementable<_Start>, "Attempt to std::prev(it, +n) on a non-bidi iterator");
::cuda::std::advance(__iter, -__n);
return __iter;
}
_CCCL_END_NAMESPACE_STD
# endif // _CCCL_HAS_HOST_STD_LIB()
#endif // _CCCL_DOXYGEN_INVOKED
#include <cuda/std/__cccl/epilogue.h>
#endif // _CUDA___ITERATOR_COUNTING_ITERATOR_H

View File

@@ -0,0 +1,325 @@
//===----------------------------------------------------------------------===//
//
// 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___ITERATOR_DISCARD_ITERATOR_H
#define _CUDA___ITERATOR_DISCARD_ITERATOR_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/__fwd/iterator.h>
#include <cuda/std/__iterator/concepts.h>
#include <cuda/std/__iterator/default_sentinel.h>
#include <cuda/std/__iterator/iterator_traits.h>
#include <cuda/std/__type_traits/is_same.h>
#include <cuda/std/__type_traits/remove_cvref.h>
#include <cuda/std/cstdint>
#include <cuda/std/__cccl/prologue.h>
_CCCL_BEGIN_NAMESPACE_CUDA
//! @addtogroup iterators
//! @{
//! @brief @c discard_iterator is an iterator which represents a special kind of pointer that ignores values written to
//! it upon dereference. This iterator is useful for ignoring the output of certain algorithms without wasting memory
//! capacity or bandwidth. @c discard_iterator may also be used to count the size of an algorithm's output which may not
//! be known a priori.
//!
//! The following code snippet demonstrates how to use @c discard_iterator to ignore one of the output ranges of
//! reduce_by_key
//!
//! @code
//! #include <cuda/iterator>
//! #include <thrust/reduce.h>
//! #include <thrust/device_vector.h>
//!
//! int main()
//! {
//! thrust::device_vector<int> keys{1, 3, 3, 3, 2, 2, 1};
//! thrust::device_vector<int> values{9, 8, 7, 6, 5, 4, 3};
//!
//! thrust::device_vector<int> result(4);
//!
//! // we are only interested in the reduced values
//! // use discard_iterator to ignore the output keys
//! thrust::reduce_by_key(keys.begin(), keys.end(),
//! values.begin(),
//! cuda::discard_iterator{},
//! result.begin());
//!
//! // result is now [9, 21, 9, 3]
//!
//! return 0;
//! }
//! @endcode
class discard_iterator
{
private:
::cuda::std::ptrdiff_t __index_ = 0;
public:
struct __discard_proxy
{
_CCCL_TEMPLATE(class _Tp)
_CCCL_REQUIRES((!::cuda::std::is_same_v<::cuda::std::remove_cvref_t<_Tp>, __discard_proxy>) )
_CCCL_API constexpr const __discard_proxy& operator=(_Tp&&) const noexcept
{
return *this;
}
};
using iterator_concept = ::cuda::std::random_access_iterator_tag;
using iterator_category = ::cuda::std::random_access_iterator_tag;
using difference_type = ::cuda::std::ptrdiff_t;
using value_type = void;
using pointer = void;
using reference = void;
//! @brief Default constructs a @c discard_iterator at index zero
_CCCL_HIDE_FROM_ABI constexpr discard_iterator() = default;
//! @brief Constructs a @c discard_iterator with a given index
//! @param __index The index used for the discard iterator
_CCCL_TEMPLATE(class _Integer)
_CCCL_REQUIRES(::cuda::std::__integer_like<_Integer>)
_CCCL_API constexpr discard_iterator(_Integer __index) noexcept
: __index_(static_cast<::cuda::std::ptrdiff_t>(__index))
{}
//! @brief Returns the stored index
[[nodiscard]] _CCCL_API constexpr difference_type index() const noexcept
{
return __index_;
}
//! @brief Dereferences the @c discard_iterator returning a proxy that discards all values that are assigned to it
[[nodiscard]] _CCCL_API constexpr __discard_proxy operator*() const noexcept
{
return {};
}
//! @brief Subscipts the @c discard_iterator returning a proxy that discards all values that are assigned to it
[[nodiscard]] _CCCL_API constexpr __discard_proxy operator[](difference_type) const noexcept
{
return {};
}
//! @brief Increments the stored index
_CCCL_API constexpr discard_iterator& operator++() noexcept
{
++__index_;
return *this;
}
//! @brief Increments the stored index
_CCCL_API constexpr discard_iterator operator++(int) noexcept
{
discard_iterator __tmp = *this;
++__index_;
return __tmp;
}
//! @brief Decrements the stored index
_CCCL_API constexpr discard_iterator& operator--() noexcept
{
--__index_;
return *this;
}
//! @brief Decrements the stored index
_CCCL_API constexpr discard_iterator operator--(int) noexcept
{
discard_iterator __tmp = *this;
--__index_;
return __tmp;
}
//! @brief Returns a copy of this @c discard_iterator advanced by a number of elements
//! @param __n The number of elements to advance
[[nodiscard]] _CCCL_API constexpr discard_iterator operator+(difference_type __n) const noexcept
{
return discard_iterator{__index_ + __n};
}
//! @brief Returns a copy of a @c discard_iterator advanced by a number of elements
//! @param __n The number of elements to advance
//! @param __x The original @c discard_iterator
[[nodiscard]] _CCCL_API friend constexpr discard_iterator
operator+(difference_type __n, const discard_iterator& __x) noexcept
{
return __x + __n;
}
//! @brief Advances the index of this @c discard_iterator by a number of elements
//! @param __n The number of elements to advance
_CCCL_API constexpr discard_iterator& operator+=(difference_type __n) noexcept
{
__index_ += __n;
return *this;
}
//! @brief Returns a copy of this @c discard_iterator decremented by a number of elements
//! @param __n The number of elements to decrement
[[nodiscard]] _CCCL_API constexpr discard_iterator operator-(difference_type __n) const noexcept
{
return discard_iterator{__index_ - __n};
}
//! @brief Returns the distance between two @c discard_iterator's
//! @param __lhs The left @c discard_iterator
//! @param __rhs The right @c discard_iterator
//! @return __rhs.__index_ - __lhs.__index_
[[nodiscard]] _CCCL_API friend constexpr difference_type
operator-(const discard_iterator& __lhs, const discard_iterator& __rhs) noexcept
{
return __rhs.__index_ - __lhs.__index_;
}
//! @brief Returns the distance between a @c default_sentinel and a @c discard_iterator
//! @param __lhs The @c discard_iterator
//! @return -__lhs.__index_
[[nodiscard]] _CCCL_API friend constexpr difference_type
operator-(const discard_iterator& __lhs, ::cuda::std::default_sentinel_t) noexcept
{
return static_cast<difference_type>(-__lhs.__index_);
}
//! @brief Returns the distance between a @c discard_iterator and a @c default_sentinel
//! @param __rhs The @c discard_iterator
//! @return __rhs.__index_
[[nodiscard]] _CCCL_API friend constexpr difference_type
operator-(::cuda::std::default_sentinel_t, const discard_iterator& __rhs) noexcept
{
return static_cast<difference_type>(__rhs.__index_);
}
//! @brief Decrements the index of the @c discard_iterator by a number of elements
//! @param __n The number of elements to decrement
_CCCL_API constexpr discard_iterator& operator-=(difference_type __n) noexcept
{
__index_ -= __n;
return *this;
}
//! @brief Compares two @c discard_iterator for equality by comparing the indices
[[nodiscard]] _CCCL_API friend constexpr bool
operator==(const discard_iterator& __lhs, const discard_iterator& __rhs) noexcept
{
return __lhs.__index_ == __rhs.__index_;
}
#if _CCCL_STD_VER <= 2017
//! @brief Compares two @c discard_iterator for inequality by comparing the indices
[[nodiscard]] _CCCL_API friend constexpr bool
operator!=(const discard_iterator& __lhs, const discard_iterator& __rhs) noexcept
{
return __lhs.__index_ != __rhs.__index_;
}
#endif // _CCCL_STD_VER <= 2017
//! @brief Compares a @c discard_iterator with @c default_sentinel
//! @returns True if the index of @param __lhs is zero
[[nodiscard]] _CCCL_API friend constexpr bool
operator==(const discard_iterator& __lhs, ::cuda::std::default_sentinel_t) noexcept
{
return __lhs.__index_ == 0;
}
#if _CCCL_STD_VER <= 2017
//! @brief Compares a @c discard_iterator with @c default_sentinel
//! @returns True if the index of @param __lhs is zero
[[nodiscard]] _CCCL_API friend constexpr bool
operator==(::cuda::std::default_sentinel_t, const discard_iterator& __rhs) noexcept
{
return __rhs.__index_ == 0;
}
//! @brief Compares a @c discard_iterator with @c default_sentinel
//! @returns True if the index of @param __lhs is not zero
[[nodiscard]] _CCCL_API friend constexpr bool
operator!=(const discard_iterator& __lhs, ::cuda::std::default_sentinel_t) noexcept
{
return __lhs.__index_ != 0;
}
//! @brief Compares a @c discard_iterator with @c default_sentinel
//! @returns True if the index of @param __lhs is not zero
[[nodiscard]] _CCCL_API friend constexpr bool
operator!=(::cuda::std::default_sentinel_t, const discard_iterator& __rhs) noexcept
{
return __rhs.__index_ != 0;
}
#endif // _CCCL_STD_VER <= 2017
#if _LIBCUDACXX_HAS_SPACESHIP_OPERATOR()
//! @brief Three-way-compares two @c discard_iterator by comparing the indices
[[nodiscard]] _CCCL_API friend constexpr strong_ordering
operator<=>(const discard_iterator& __lhs, const discard_iterator& __rhs) noexcept
{
return __lhs.__index_ <=> __rhs.__index_;
}
#else // ^^^ _LIBCUDACXX_HAS_SPACESHIP_OPERATOR() ^^^ / vvv !_LIBCUDACXX_HAS_SPACESHIP_OPERATOR() vvv
//! @brief Compares two @c discard_iterator for less than by comparing the indices
[[nodiscard]] _CCCL_API friend constexpr bool
operator<(const discard_iterator& __lhs, const discard_iterator& __rhs) noexcept
{
return __lhs.__index_ < __rhs.__index_;
}
//! @brief Compares two @c discard_iterator for less equal by comparing the indices
[[nodiscard]] _CCCL_API friend constexpr bool
operator<=(const discard_iterator& __lhs, const discard_iterator& __rhs) noexcept
{
return __lhs.__index_ <= __rhs.__index_;
}
//! @brief Compares two @c discard_iterator for greater than by comparing the indices
[[nodiscard]] _CCCL_API friend constexpr bool
operator>(const discard_iterator& __lhs, const discard_iterator& __rhs) noexcept
{
return __lhs.__index_ > __rhs.__index_;
}
//! @brief Compares two @c discard_iterator for greater equal by comparing the indices
[[nodiscard]] _CCCL_API friend constexpr bool
operator>=(const discard_iterator& __lhs, const discard_iterator& __rhs) noexcept
{
return __lhs.__index_ >= __rhs.__index_;
}
#endif // _LIBCUDACXX_HAS_SPACESHIP_OPERATOR()
};
//! @brief Creates a @c discard_iterator from an optional index.
//! @param __index The index of the @c discard_iterator within a range. The default index is @c 0.
//! @return A new @c discard_iterator with @c __index as the counter.
//! @relates discard_iterator
_CCCL_TEMPLATE(class _Integer = ::cuda::std::ptrdiff_t)
_CCCL_REQUIRES(::cuda::std::__integer_like<_Integer>)
[[nodiscard]] _CCCL_API constexpr discard_iterator make_discard_iterator(_Integer __index = 0)
{
return discard_iterator{__index};
}
//! @}
_CCCL_END_NAMESPACE_CUDA
#include <cuda/std/__cccl/epilogue.h>
#endif // _CUDA___ITERATOR_DISCARD_ITERATOR_H

View File

@@ -0,0 +1,477 @@
//===----------------------------------------------------------------------===//
//
// 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___ITERATOR_PERMUTATION_ITERATOR_H
#define _CUDA___ITERATOR_PERMUTATION_ITERATOR_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/__fwd/iterator.h>
#include <cuda/std/__concepts/equality_comparable.h>
#include <cuda/std/__concepts/totally_ordered.h>
#include <cuda/std/__iterator/concepts.h>
#include <cuda/std/__iterator/iterator_traits.h>
#include <cuda/std/__type_traits/is_nothrow_copy_constructible.h>
#include <cuda/std/__type_traits/is_nothrow_default_constructible.h>
#include <cuda/std/__type_traits/is_nothrow_move_constructible.h>
#include <cuda/std/__utility/declval.h>
#include <cuda/std/__utility/move.h>
#if _LIBCUDACXX_HAS_SPACESHIP_OPERATOR()
# include <cuda/std/detail/libcxx/include/compare>
#endif // _LIBCUDACXX_HAS_SPACESHIP_OPERATOR()
#include <cuda/std/__cccl/prologue.h>
_CCCL_BEGIN_NAMESPACE_CUDA
//! @addtogroup iterators
//! @{
//! @brief @c permutation_iterator is an iterator which represents a pointer into a reordered view of a given range.
//! @c permutation_iterator is an imprecise name; the reordered view need not be a strict permutation. This iterator is
//! useful for fusing a scatter or gather operation with other algorithms.
//!
//! This iterator takes two arguments:
//!
//! - an iterator to the range @c V on which the "permutation" will be applied, referred to as @c iter below
//! - an iterator to a range of indices defining the reindexing scheme that determines how the elements of @c V will
//! be permuted, referred to as @c index below
//!
//! Note that @c permutation_iterator is not limited to strict permutations of the given range @c V. The distance
//! between begin and end of the reindexing iterators is allowed to be smaller compared to the size of the range @c V,
//! in which case the @c permutation_iterator only provides a "permutation" of a subset of @c V. The indices do not
//! need to be unique. In this same context, it must be noted that the past-the-end @c permutation_iterator is
//! completely defined by means of the past-the-end iterator to the indices.
//!
//! The following code snippet demonstrates how to create a @c permutation_iterator which represents a reordering of the
//! contents of a @c device_vector.
//!
//! @code
//! #include <cuda/iterator>
//! #include <thrust/device_vector.h>
//! ...
//! thrust::device_vector<float> values{10.0f, 20.0f, 30.0f, 40.0f, 50.0f, 60.0f, 70.0f, 80.0f};
//! thrust::device_vector<int> indices{2, 6, 1, 3};
//!
//! using ElementIterator = thrust::device_vector<float>::iterator;
//! using IndexIterator = thrust::device_vector<int>::iterator;
//!
//! cuda::permutation_iterator<ElementIterator,IndexIterator> iter(values.begin(), indices.begin());
//!
//! *iter; // returns 30.0f;
//! iter[0]; // returns 30.0f;
//! iter[1]; // returns 70.0f;
//! iter[2]; // returns 20.0f;
//! iter[3]; // returns 40.0f;
//!
//! // iter[4] is an out-of-bounds error
//!
//! *iter = -1.0f; // sets values[2] to -1.0f;
//! iter[0] = -1.0f; // sets values[2] to -1.0f;
//! iter[1] = -1.0f; // sets values[6] to -1.0f;
//! iter[2] = -1.0f; // sets values[1] to -1.0f;
//! iter[3] = -1.0f; // sets values[3] to -1.0f;
//!
//! // values is now {10, -1, -1, -1, 50, 60, -1, 80}
//! @endcode
template <class _Iter, class _Index>
class permutation_iterator
{
private:
_Iter __iter_;
_Index __index_;
#ifndef _CCCL_DOXYGEN_INVOKED // Internal helpers
// We need to factor these out because old gcc chokes with using arguments in friend functions
template <class _Iter1>
static constexpr bool __nothrow_plus =
::cuda::std::is_nothrow_copy_constructible_v<_Iter1> && ::cuda::std::is_nothrow_copy_constructible_v<_Index>
&& noexcept(::cuda::std::declval<const _Index&>() + ::cuda::std::iter_difference_t<_Index>());
template <class _Iter1>
static constexpr bool __nothrow_minus =
::cuda::std::is_nothrow_copy_constructible_v<_Iter1> && ::cuda::std::is_nothrow_copy_constructible_v<_Index>
&& noexcept(::cuda::std::declval<const _Index&>() - ::cuda::std::iter_difference_t<_Index>());
template <class _Iter1>
static constexpr bool __nothrow_difference =
noexcept(::cuda::std::declval<_Iter1>() - ::cuda::std::declval<_Iter1>());
template <class _Iter1, class _Iter2>
static constexpr bool __nothrow_equality = noexcept(::cuda::std::declval<_Iter1>() == ::cuda::std::declval<_Iter2>());
template <class _Iter1, class _Iter2>
static constexpr bool __nothrow_less_than = noexcept(::cuda::std::declval<_Iter1>() < ::cuda::std::declval<_Iter2>());
template <class _Iter1, class _Iter2>
static constexpr bool __nothrow_less_equal =
noexcept(::cuda::std::declval<_Iter1>() <= ::cuda::std::declval<_Iter2>());
template <class _Iter1, class _Iter2>
static constexpr bool __nothrow_greater_than =
noexcept(::cuda::std::declval<_Iter1>() > ::cuda::std::declval<_Iter2>());
template <class _Iter1, class _Iter2>
static constexpr bool __nothrow_greater_equal =
noexcept(::cuda::std::declval<_Iter1>() >= ::cuda::std::declval<_Iter2>());
#endif // _CCCL_DOXYGEN_INVOKED
public:
using iterator_type = _Iter;
using iterator_concept = ::cuda::std::random_access_iterator_tag;
using iterator_category = ::cuda::std::random_access_iterator_tag;
using value_type = ::cuda::std::iter_value_t<_Iter>;
using __iter_difference_t = ::cuda::std::iter_difference_t<_Iter>;
using difference_type = ::cuda::std::iter_difference_t<_Index>;
using __index_value_t = ::cuda::std::iter_value_t<_Index>;
//! Ensure that the user passes an iterator to something interger_like
static_assert(::cuda::std::__integer_like<__index_value_t>,
"cuda::permutation_iterator: _Index must be an iterator to integer_like");
//! Ensure that the index value_type is convertible to difference_type
static_assert(::cuda::std::is_convertible_v<__index_value_t, difference_type>,
"cuda::permutation_iterator: _Indexs value type must be convertible to iter_difference<Iter>");
//! To actually use operator+ we need the index iterator to be random access
static_assert(::cuda::std::__has_random_access_traversal<_Index>,
"cuda::permutation_iterator: _Index must be a random access iterator!");
//! To actually use operator+ we need the base iterator to be random access
static_assert(::cuda::std::__has_random_access_traversal<_Iter>,
"cuda::permutation_iterator: _Iter must be a random access iterator!");
//! @brief Default constructs an @c permutation_iterator with a value initialized iterator and index
_CCCL_EXEC_CHECK_DISABLE
_CCCL_TEMPLATE(class _Iter2 = _Iter, class _Index2 = _Index)
_CCCL_REQUIRES(::cuda::std::default_initializable<_Iter2> _CCCL_AND ::cuda::std::default_initializable<_Index2>)
_CCCL_API constexpr permutation_iterator() noexcept(
::cuda::std::is_nothrow_default_constructible_v<_Iter2> && ::cuda::std::is_nothrow_default_constructible_v<_Index2>)
: __iter_()
, __index_()
{}
//! @brief Constructs an @c permutation_iterator from an iterator and an optional index
//! @param __iter The iterator to index from
//! @param __index The iterator with the permutations
_CCCL_EXEC_CHECK_DISABLE
_CCCL_API constexpr permutation_iterator(_Iter __iter, _Index __index) noexcept(
::cuda::std::is_nothrow_copy_constructible_v<_Iter> && ::cuda::std::is_nothrow_copy_constructible_v<_Index>)
: __iter_(__iter)
, __index_(__index)
{}
//! @brief Returns a const reference to the stored base iterator @c iter
[[nodiscard]] _CCCL_API constexpr const _Iter& base() const& noexcept
{
return __iter_;
}
//! @brief Extracts the stored base iterator @c iter
_CCCL_EXEC_CHECK_DISABLE
[[nodiscard]] _CCCL_API constexpr _Iter base() && noexcept(::cuda::std::is_nothrow_move_constructible_v<_Iter>)
{
return ::cuda::std::move(__iter_);
}
//! @cond
//! @brief Returns a const reference to the stored index iterator @c index
[[nodiscard]] _CCCL_API constexpr const _Index& __index() const noexcept
{
return __index_;
}
//! @endcond
//! @brief Returns the current index
//! @return Equivalent to ``*index``
_CCCL_EXEC_CHECK_DISABLE
[[nodiscard]] _CCCL_API constexpr difference_type index() const noexcept
{
return static_cast<difference_type>(*__index_);
}
//! @brief Dereferences the @c permutation_iterator
//! @return Equivalent to ``iter[*index]``
_CCCL_EXEC_CHECK_DISABLE
[[nodiscard]] _CCCL_API constexpr decltype(auto)
operator*() noexcept(noexcept(__iter_[static_cast<__iter_difference_t>(*__index_)]))
{
return __iter_[static_cast<__iter_difference_t>(*__index_)];
}
//! @brief Dereferences the @c permutation_iterator
//! @return Equivalent to ``iter[*index]``
_CCCL_EXEC_CHECK_DISABLE
_CCCL_TEMPLATE(class _Iter2 = _Iter)
_CCCL_REQUIRES(::cuda::std::__dereferenceable<const _Iter2>)
[[nodiscard]] _CCCL_API constexpr decltype(auto) operator*() const
noexcept(noexcept(__iter_[static_cast<__iter_difference_t>(*__index_)]))
{
return __iter_[static_cast<__iter_difference_t>(*__index_)];
}
//! @brief Subscripts the @c permutation_iterator by an offset
//! @param __n The additional offset
//! @return Equivalent to ``iter[index[__n]]``
_CCCL_EXEC_CHECK_DISABLE
[[nodiscard]] _CCCL_API constexpr decltype(auto)
operator[](difference_type __n) noexcept(noexcept(__iter_[static_cast<__iter_difference_t>(__index_[__n])]))
{
return __iter_[static_cast<__iter_difference_t>(__index_[__n])];
}
//! @brief Subscripts the @c permutation_iterator by an offset
//! @param __n The additional offset
//! @return Equivalent to ``iter[index[__n]]``
_CCCL_EXEC_CHECK_DISABLE
_CCCL_TEMPLATE(class _Iter2 = _Iter)
_CCCL_REQUIRES(::cuda::std::__dereferenceable<const _Iter2>)
[[nodiscard]] _CCCL_API constexpr decltype(auto) operator[](difference_type __n) const
noexcept(noexcept(__iter_[static_cast<__iter_difference_t>(__index_[__n])]))
{
return __iter_[static_cast<__iter_difference_t>(__index_[__n])];
}
//! @brief Increments the @c permutation_iterator
//! @return Equivalent to ``++index``
_CCCL_EXEC_CHECK_DISABLE
_CCCL_API constexpr permutation_iterator& operator++() noexcept(noexcept(++__index_))
{
++__index_;
return *this;
}
//! @brief Increments the @c permutation_iterator
//! @return Equivalent to ``index++``
_CCCL_EXEC_CHECK_DISABLE
_CCCL_API constexpr permutation_iterator operator++(int) noexcept(
noexcept(++__index_)
&& ::cuda::std::is_nothrow_copy_constructible_v<_Iter> && ::cuda::std::is_nothrow_copy_constructible_v<_Index>)
{
permutation_iterator __tmp = *this;
++__index_;
return __tmp;
}
//! @brief Increments the @c permutation_iterator
//! @return Equivalent to ``--index``
_CCCL_EXEC_CHECK_DISABLE
_CCCL_API constexpr permutation_iterator& operator--() noexcept(noexcept(--__index_))
{
--__index_;
return *this;
}
//! @brief Increments the @c permutation_iterator
//! @return Equivalent to ``index++``
_CCCL_EXEC_CHECK_DISABLE
_CCCL_API constexpr permutation_iterator operator--(int) noexcept(
noexcept(--__index_)
&& ::cuda::std::is_nothrow_copy_constructible_v<_Iter> && ::cuda::std::is_nothrow_copy_constructible_v<_Index>)
{
permutation_iterator __tmp = *this;
--__index_;
return __tmp;
}
#ifndef _CCCL_DOXYGEN_INVOKED // Doxygen has issues with constexpr friend operators
//! @brief Advances a @c permutation_iterator by a given number of elements
//! @param __iter The original @c permutation_iterator
//! @param __n The number of elements to advance
//! @return Equivalent to ``permutation_iterator{iter, index + __n}``
_CCCL_EXEC_CHECK_DISABLE
template <class _Iter2 = _Iter> // Must be template, or the compiler complains about a nonliteral return type
[[nodiscard]] _CCCL_API friend constexpr permutation_iterator
operator+(const permutation_iterator& __iter, difference_type __n) noexcept(__nothrow_plus<_Iter2>)
{
return permutation_iterator{__iter.__iter_, __iter.__index_ + __n};
}
//! @brief Advances a @c permutation_iterator by a given number of elements
//! @param __n The number of elements to advance
//! @param __iter The original @c permutation_iterator
//! @return Equivalent to ``permutation_iterator{iter, index + __n}``
_CCCL_EXEC_CHECK_DISABLE
template <class _Iter2 = _Iter> // Must be template, or the compiler complains about a nonliteral return type
[[nodiscard]] _CCCL_API friend constexpr permutation_iterator
operator+(difference_type __n, const permutation_iterator& __iter) noexcept(__nothrow_plus<_Iter2>)
{
return permutation_iterator{__iter.__iter_, __iter.__index_ + __n};
}
//! @brief Decrements a @c permutation_iterator by a given number of elements
//! @param __iter The original @c permutation_iterator
//! @param __n The number of elements to decrement
//! @return Equivalent to ``permutation_iterator{iter, index - __n}``
_CCCL_EXEC_CHECK_DISABLE
template <class _Iter2 = _Iter> // Must be template, or the compiler complains about a nonliteral return type
[[nodiscard]] _CCCL_API friend constexpr permutation_iterator
operator-(const permutation_iterator& __iter, difference_type __n) noexcept(__nothrow_minus<_Iter2>)
{
return permutation_iterator{__iter.__iter_, __iter.__index_ - __n};
}
#endif // !_CCCL_DOXYGEN_INVOKED
//! @brief Advances the @c permutation_iterator by a given number of elements
//! @param __n The number of elements to advance
//! @return Equivalent to ``index + __n``
_CCCL_EXEC_CHECK_DISABLE
_CCCL_API constexpr permutation_iterator& operator+=(difference_type __n) noexcept(noexcept(__index_ += __n))
{
__index_ += __n;
return *this;
}
//! @brief Decrements the @c permutation_iterator by a given number of elements
//! @param __n The number of elements to decrement
//! @return Equivalent to ``index - __n``
_CCCL_EXEC_CHECK_DISABLE
_CCCL_API constexpr permutation_iterator& operator-=(difference_type __n) noexcept(noexcept(__index_ -= __n))
{
__index_ -= __n;
return *this;
}
//! @brief Returns the distance between two @c permutation_iterators.
//! @return Equivalent to ``__lhs.index - __rhs.index``
_CCCL_EXEC_CHECK_DISABLE
[[nodiscard]] _CCCL_API friend constexpr difference_type
operator-(const permutation_iterator& __lhs, const permutation_iterator& __rhs) noexcept(__nothrow_difference<_Index>)
{
return __lhs.__index_ - __rhs.__index();
}
//! @brief Compares two @c permutation_iterator for equality by comparing @c index
//! @return Equivalent to ``__lhs.index == __rhs.index``
_CCCL_EXEC_CHECK_DISABLE
_CCCL_TEMPLATE(class _OtherIter, class _OtherOffset)
_CCCL_REQUIRES(::cuda::std::equality_comparable_with<_Iter, _OtherIter>)
[[nodiscard]] _CCCL_API friend constexpr bool operator==(
const permutation_iterator& __lhs,
const permutation_iterator<_OtherIter, _OtherOffset>& __rhs) noexcept(__nothrow_equality<_Index, _OtherOffset>)
{
return __lhs.__index_ == __rhs.__index();
}
#if _CCCL_STD_VER <= 2017
//! @brief Compares two @c permutation_iterator for inequality by comparing @c index
//! @return Equivalent to ``__lhs.index != __rhs.index``
_CCCL_EXEC_CHECK_DISABLE
_CCCL_TEMPLATE(class _OtherIter, class _OtherOffset)
_CCCL_REQUIRES(::cuda::std::equality_comparable_with<_Iter, _OtherIter>)
[[nodiscard]] _CCCL_API friend constexpr bool operator!=(
const permutation_iterator& __lhs,
const permutation_iterator<_OtherIter, _OtherOffset>& __rhs) noexcept(__nothrow_equality<_Index, _OtherOffset>)
{
return !(__lhs.__index_ == __rhs.__index());
}
#endif // _CCCL_STD_VER <= 2017
#if _LIBCUDACXX_HAS_SPACESHIP_OPERATOR()
template <class _Iter1, class _Iter2>
static constexpr bool __nothrow_three_way =
noexcept(::cuda::std::declval<_Iter1>() <=> ::cuda::std::declval<_Iter2>());
//! @brief Three-way-compares two @c permutation_iterator for inequality by comparing @c index
//! they point at
//! @return Equivalent to ``__lhs.index <=> __rhs.index``
_CCCL_EXEC_CHECK_DISABLE
_CCCL_TEMPLATE(class _OtherIter, class _OtherOffset)
_CCCL_REQUIRES(::cuda::std::three_way_comparable_with<_Index, _OtherOffset>)
[[nodiscard]] _CCCL_API friend constexpr strong_ordering operator<=>(
const permutation_iterator& __lhs,
const permutation_iterator<_OtherIter, _OtherOffset>& __rhs) noexcept(__nothrow_three_way<_Index, _OtherOffset>)
{
return __lhs.__index_ <=> __rhs.__index();
}
#else // ^^^ _LIBCUDACXX_HAS_SPACESHIP_OPERATOR() ^^^ / vvv !_LIBCUDACXX_HAS_SPACESHIP_OPERATOR() vvv
//! @brief Compares two @c permutation_iterator for less than by comparing @c index
//! @return Equivalent to ``__lhs.index < __rhs.index``
_CCCL_EXEC_CHECK_DISABLE
_CCCL_TEMPLATE(class _OtherIter, class _OtherOffset)
_CCCL_REQUIRES(::cuda::std::totally_ordered_with<_Index, _OtherOffset>)
[[nodiscard]] _CCCL_API friend constexpr bool operator<(
const permutation_iterator& __lhs,
const permutation_iterator<_OtherIter, _OtherOffset>& __rhs) noexcept(__nothrow_less_than<_Index, _OtherOffset>)
{
return __lhs.__index_ < __rhs.__index();
}
//! @brief Compares two @c permutation_iterator for less equal by comparing @c index
//! @return Equivalent to ``__lhs.index <= __rhs.index``
_CCCL_EXEC_CHECK_DISABLE
_CCCL_TEMPLATE(class _OtherIter, class _OtherOffset)
_CCCL_REQUIRES(::cuda::std::totally_ordered_with<_Index, _OtherOffset>)
[[nodiscard]] _CCCL_API friend constexpr bool operator<=(
const permutation_iterator& __lhs,
const permutation_iterator<_OtherIter, _OtherOffset>& __rhs) noexcept(__nothrow_less_equal<_Index, _OtherOffset>)
{
return __lhs.__index_ <= __rhs.__index();
}
//! @brief Compares two @c permutation_iterator for greater than by comparing @c index
//! @return Equivalent to ``__lhs.index > __rhs.index``
_CCCL_EXEC_CHECK_DISABLE
_CCCL_TEMPLATE(class _OtherIter, class _OtherOffset)
_CCCL_REQUIRES(::cuda::std::totally_ordered_with<_Index, _OtherOffset>)
[[nodiscard]] _CCCL_API friend constexpr bool operator>(
const permutation_iterator& __lhs,
const permutation_iterator<_OtherIter, _OtherOffset>& __rhs) noexcept(__nothrow_greater_than<_Index, _OtherOffset>)
{
return __lhs.__index_ > __rhs.__index();
}
//! @brief Compares two @c permutation_iterator for greater equal by comparing @c index
//! @return Equivalent to ``__lhs.index >= __rhs.index``
_CCCL_EXEC_CHECK_DISABLE
_CCCL_TEMPLATE(class _OtherIter, class _OtherOffset)
_CCCL_REQUIRES(::cuda::std::totally_ordered_with<_Index, _OtherOffset>)
[[nodiscard]] _CCCL_API friend constexpr bool operator>=(
const permutation_iterator& __lhs,
const permutation_iterator<_OtherIter, _OtherOffset>& __rhs) noexcept(__nothrow_greater_equal<_Index, _OtherOffset>)
{
return __lhs.__index_ >= __rhs.__index();
}
#endif // !_LIBCUDACXX_HAS_SPACESHIP_OPERATOR()
};
#ifndef _CCCL_DOXYGEN_INVOKED
_CCCL_TEMPLATE(class _Iter, class _Index)
_CCCL_REQUIRES(
::cuda::std::__has_random_access_traversal<_Iter> _CCCL_AND ::cuda::std::__has_random_access_traversal<_Index>)
_CCCL_DEDUCTION_GUIDE_ATTRIBUTES permutation_iterator(_Iter, _Index) -> permutation_iterator<_Iter, _Index>;
#endif // _CCCL_DOXYGEN_INVOKED
//! @brief Creates an @c permutation_iterator from a base iterator and an iterator to an integral index
//! @param __iter The iterator
//! @param __index The iterator to an integral index
//! @relates permutation_iterator
_CCCL_TEMPLATE(class _Iter, class _Index)
_CCCL_REQUIRES(
::cuda::std::__has_random_access_traversal<_Iter> _CCCL_AND ::cuda::std::__has_random_access_traversal<_Index>)
[[nodiscard]] _CCCL_API constexpr permutation_iterator<_Iter, _Index>
make_permutation_iterator(_Iter __iter, _Index __index) noexcept(
::cuda::std::is_nothrow_copy_constructible_v<_Iter> && ::cuda::std::is_nothrow_copy_constructible_v<_Index>)
{
return permutation_iterator<_Iter, _Index>{__iter, __index};
}
//! @}
_CCCL_END_NAMESPACE_CUDA
#include <cuda/std/__cccl/epilogue.h>
#endif // _CUDA___ITERATOR_PERMUTATION_ITERATOR_H

View File

@@ -0,0 +1,363 @@
//===----------------------------------------------------------------------===//
//
// 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___ITERATOR_SHUFFLE_ITERATOR_H
#define _CUDA___ITERATOR_SHUFFLE_ITERATOR_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/__fwd/iterator.h>
#if _LIBCUDACXX_HAS_SPACESHIP_OPERATOR()
# include <cuda/std/__compare/three_way_comparable.h>
#endif // _LIBCUDACXX_HAS_SPACESHIP_OPERATOR()
#include <cuda/__random/random_bijection.h>
#include <cuda/std/__concepts/constructible.h>
#include <cuda/std/__random/is_valid.h>
#include <cuda/std/__type_traits/is_constructible.h>
#include <cuda/std/__type_traits/is_integral.h>
#include <cuda/std/__type_traits/is_nothrow_constructible.h>
#include <cuda/std/__type_traits/is_nothrow_copy_constructible.h>
#include <cuda/std/__type_traits/is_nothrow_default_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/make_signed.h>
#include <cuda/std/__utility/forward.h>
#include <cuda/std/__utility/move.h>
#include <cuda/std/cstdint>
#include <cuda/std/__cccl/prologue.h>
_CCCL_BEGIN_NAMESPACE_CUDA
_CCCL_BEGIN_NV_DIAG_SUPPRESS(20011) // calling a __host__ function from a __host__ __device__ function shuffle_iterator
// is not allowed
//! @addtogroup iterators
//! @{
//! @brief Verifies that a given type @tparam _Bijection is a valid bijection function.
//! It verifies
//! * The bijection has a type alias ``index_type`` that satisfies ``integral``
//! * The bijection has a non-mutable member function size() that returns the number of elements as ``index_type``
//! * The bijection has a non-mutable call operator that takes a value of type ``index_type`` in the range
//! ``[0, size())`` and projects it into the range ``[0, size())``
template <class _Bijection>
_CCCL_CONCEPT __is_bijection = _CCCL_REQUIRES_EXPR((_Bijection), const _Bijection& __fun)(
typename(typename _Bijection::index_type),
requires(::cuda::std::is_integral_v<typename _Bijection::index_type>),
requires(::cuda::std::is_same_v<decltype(__fun.size()), typename _Bijection::index_type>),
requires(
::cuda::std::is_same_v<decltype(__fun(typename _Bijection::index_type(0))), typename _Bijection::index_type>));
//! @brief @c shuffle_iterator is an iterator which generates a sequence of integral values representing a random
//! permutation.
//! @tparam _IndexType The type of the index to shuffle. Defaults to uint64_t
//! @tparam _BijectionFunc The bijection to use. This should be a bijective function that maps [0..n) -> [0..n). It must
//! be deterministic and stateless. Defaults to cuda::random_biijection<_IndexType>
//!
//! @c shuffle_iterator is an iterator which generates a sequence of values representing a random permutation. This
//! iterator is useful for working with random permutations of a range without explicitly storing them in memory. The
//! shuffle iterator is also useful for sampling from a range by selecting only a subset of the elements in the
//! permutation.
//!
//! The following code snippet demonstrates how to create a @c shuffle_iterator which generates a random permutation
//! of the range[0, 4)
//!
//! @code
//! #include <cuda/iterator>
//! ...
//! // create a shuffle_iterator
//! cuda::shuffle_iterator iterator{cuda::random_bijection{4, cuda::std::minstd_rand(0xDEADBEEF)}};
//! // iterator[0] returns 1
//! // iterator[1] returns 3
//! // iterator[2] returns 2
//! // iterator[3] returns 0
//! @endcode
template <class _IndexType, class _Bijection>
class shuffle_iterator
{
private:
_Bijection __bijection_;
_IndexType __current_;
static_assert(::cuda::std::is_integral_v<_IndexType>, "_IndexType must be an integral type");
static_assert(__is_bijection<_Bijection>, "_Bijection must be a valid bijection function");
public:
using iterator_category = ::cuda::std::random_access_iterator_tag;
using iterator_concept = ::cuda::std::random_access_iterator_tag;
using value_type = _IndexType;
using difference_type = ::cuda::std::make_signed_t<value_type>;
// Those are technically not to spec, but pre-ranges iterator_traits do not work properly with iterators that do not
// define all 5 aliases, see https://en.cppreference.com/w/cpp/iterator/iterator_traits.html
using reference = _IndexType;
using pointer = void;
_CCCL_EXEC_CHECK_DISABLE // NVCC 12.0 fails to default construct when _CCCL_TEMPLATE is used
template <class _Bijection2 = _Bijection,
::cuda::std::enable_if_t<::cuda::std::default_initializable<_Bijection2>, int> = 0>
_CCCL_API constexpr shuffle_iterator() noexcept(::cuda::std::is_nothrow_default_constructible_v<_Bijection2>)
: __bijection_()
, __current_(0)
{}
//! @brief Constructs a @c shuffle_iterator from a given bijection and an optional start position
//! @param __bijection The bijection representing the shuffled integer sequence
//! @param __start The position of the iterator in the shuffled integer sequence
_CCCL_EXEC_CHECK_DISABLE
_CCCL_API constexpr shuffle_iterator(_Bijection __bijection, value_type __start = 0) noexcept(
::cuda::std::is_nothrow_move_constructible_v<_Bijection>)
: __bijection_(::cuda::std::move(__bijection))
, __current_(__start)
{}
//! @brief Constructs a @c shuffle_iterator by constructing the bijection function in place and an optional start
//! position
//! @param __num_elements The size of the bijection sequence
//! @param __gen The random number generator to initialize the bijection
//! @param __start The optional stating index of the @c shuffle_iterator in the bijection sequence
_CCCL_EXEC_CHECK_DISABLE
template <class _RNG> // constraining here breaks CTAD
_CCCL_API explicit constexpr shuffle_iterator(value_type __num_elements, _RNG&& __gen, value_type __start = 0) //
noexcept(::cuda::std::is_nothrow_constructible_v<_Bijection, value_type, _RNG>)
: __bijection_(__num_elements, ::cuda::std::forward<_RNG>(__gen))
, __current_(__start)
{}
//! @brief Dereferences the @c shuffle_iterator by invoking the bijection with the stored index
_CCCL_EXEC_CHECK_DISABLE
[[nodiscard]] _CCCL_API constexpr value_type operator*() const noexcept(noexcept(__bijection_(0)))
{
_CCCL_ASSERT(__current_ < static_cast<value_type>(__bijection_.size()),
"shuffle_iterator::operator*: Trying to dereference a shuffle_iterator past the end!");
return static_cast<value_type>(__bijection_(static_cast<typename _Bijection::index_type>(__current_)));
}
//! @brief Subscripts the @c shuffle_iterator by invoking the bijection with the stored index advanced by a given
//! number of elements
//! @param __n The additional number of elements
_CCCL_EXEC_CHECK_DISABLE
[[nodiscard]] _CCCL_API constexpr value_type operator[](difference_type __n) const noexcept(noexcept(__bijection_(0)))
{
_CCCL_ASSERT(static_cast<value_type>(static_cast<difference_type>(__current_) + __n)
< static_cast<value_type>(__bijection_.size()),
"shuffle_iterator::operator*: Trying to subscript a shuffle_iterator past the end!");
return static_cast<value_type>(__bijection_(static_cast<typename _Bijection::index_type>(__current_ + __n)));
}
//! @brief Increments the @c shuffle_iterator
_CCCL_EXEC_CHECK_DISABLE
_CCCL_API constexpr shuffle_iterator& operator++() noexcept
{
++__current_;
return *this;
}
//! @brief Increments the @c shuffle_iterator
_CCCL_EXEC_CHECK_DISABLE
_CCCL_API constexpr shuffle_iterator operator++(int) noexcept(::cuda::std::is_nothrow_copy_constructible_v<_Bijection>)
{
auto __tmp = *this;
++__current_;
return __tmp;
}
//! @brief Decrements the @c shuffle_iterator
_CCCL_EXEC_CHECK_DISABLE
_CCCL_API constexpr shuffle_iterator& operator--() noexcept
{
--__current_;
return *this;
}
//! @brief Decrements the @c shuffle_iterator
_CCCL_EXEC_CHECK_DISABLE
[[nodiscard]] _CCCL_API constexpr shuffle_iterator
operator--(int) noexcept(::cuda::std::is_nothrow_copy_constructible_v<_Bijection>)
{
auto __tmp = *this;
--__current_;
return __tmp;
}
//! @brief Advances the @c shuffle_iterator by a given number of elements
//! @param __n The number of elements to advance
_CCCL_EXEC_CHECK_DISABLE
_CCCL_API constexpr shuffle_iterator& operator+=(difference_type __n) noexcept
{
#if _CCCL_COMPILER(MSVC) // C4308: negative integral constant converted to unsigned type
__current_ = static_cast<value_type>(static_cast<difference_type>(__current_) + __n);
#else // ^^^ _CCCL_COMPILER(MSVC) ^^^ / vvv !_CCCL_COMPILER(MSVC) vvv
__current_ += __n;
#endif // !_CCCL_COMPILER(MSVC)
return *this;
}
//! @brief Returns a copy of a @c shuffle_iterator incremented by a given number of elements
//! @param __iter The @c shuffle_iterator to copy
//! @param __n The number of elements to increment
_CCCL_EXEC_CHECK_DISABLE
template <int = 0> // Must be template, or the compiler complains about a nonliteral return type
[[nodiscard]]
_CCCL_API friend constexpr shuffle_iterator operator+(shuffle_iterator __iter, difference_type __n) noexcept
{
#if _CCCL_COMPILER(MSVC) // C4308: negative integral constant converted to unsigned type
__iter.__current_ = static_cast<value_type>(static_cast<difference_type>(__iter.__current_) + __n);
#else // ^^^ _CCCL_COMPILER(MSVC) ^^^ / vvv !_CCCL_COMPILER(MSVC) vvv
__iter.__current_ += __n;
#endif // !_CCCL_COMPILER(MSVC)
return __iter;
}
//! @brief Returns a copy of a @c shuffle_iterator incremented by a given number of elements
//! @param __n The number of elements to increment
//! @param __iter The @c shuffle_iterator to copy
_CCCL_EXEC_CHECK_DISABLE
template <int = 0> // Must be template, or the compiler complains about a nonliteral return type
[[nodiscard]]
_CCCL_API friend constexpr shuffle_iterator operator+(difference_type __n, shuffle_iterator __iter) noexcept
{
#if _CCCL_COMPILER(MSVC) // C4308: negative integral constant converted to unsigned type
__iter.__current_ = static_cast<value_type>(static_cast<difference_type>(__iter.__current_) + __n);
#else // ^^^ _CCCL_COMPILER(MSVC) ^^^ / vvv !_CCCL_COMPILER(MSVC) vvv
__iter.__current_ += __n;
#endif // !_CCCL_COMPILER(MSVC)
return __iter;
}
//! @brief Decrements the @c shuffle_iterator by a given number of elements
//! @param __n The number of elements to decrement
_CCCL_EXEC_CHECK_DISABLE
_CCCL_API constexpr shuffle_iterator& operator-=(difference_type __n) noexcept
{
#if _CCCL_COMPILER(MSVC) // C4308: negative integral constant converted to unsigned type
__current_ = static_cast<value_type>(static_cast<difference_type>(__current_) - __n);
#else // ^^^ _CCCL_COMPILER(MSVC) ^^^ / vvv !_CCCL_COMPILER(MSVC) vvv
__current_ -= __n;
#endif // !_CCCL_COMPILER(MSVC)
return *this;
}
//! @brief Returns a copy of a @c shuffle_iterator decremented by a given number of elements
//! @param __iter The @c shuffle_iterator to copy
//! @param __n The number of elements to decrement
_CCCL_EXEC_CHECK_DISABLE
template <int = 0> // Must be template, or the compiler complains about a nonliteral return type
[[nodiscard]]
_CCCL_API friend constexpr shuffle_iterator operator-(shuffle_iterator __iter, difference_type __n) noexcept
{
#if _CCCL_COMPILER(MSVC) // C4308: negative integral constant converted to unsigned type
__iter.__current_ = static_cast<value_type>(static_cast<difference_type>(__iter.__current_) - __n);
#else // ^^^ _CCCL_COMPILER(MSVC) ^^^ / vvv !_CCCL_COMPILER(MSVC) vvv
__iter.__current_ -= __n;
#endif // !_CCCL_COMPILER(MSVC)
return __iter;
}
//! @brief Calculates the distance between two @c shuffle_iterator
[[nodiscard]] _CCCL_API friend constexpr difference_type
operator-(const shuffle_iterator& __x, const shuffle_iterator& __y) noexcept
{
return static_cast<difference_type>(__x.__current_ - __y.__current_);
}
//! @brief Compares two @c shuffle_iterator for equality by comparing their index
[[nodiscard]] _CCCL_API friend constexpr bool
operator==(const shuffle_iterator& __x, const shuffle_iterator& __y) noexcept
{
return __x.__current_ == __y.__current_;
}
#if _CCCL_STD_VER <= 2017
//! @brief Compares two @c shuffle_iterator for inequality by comparing their index
[[nodiscard]] _CCCL_API friend constexpr bool
operator!=(const shuffle_iterator& __x, const shuffle_iterator& __y) noexcept
{
return __x.__current_ != __y.__current_;
}
#endif // _CCCL_STD_VER <= 2017
#if _LIBCUDACXX_HAS_SPACESHIP_OPERATOR()
//! @brief Three-way compares two @c shuffle_iterator for less equal by comparing their index
[[nodiscard]] _CCCL_API friend constexpr ::cuda::std::strong_ordering
operator<=>(const shuffle_iterator& __x, const shuffle_iterator& __y) noexcept
{
return __x.__current_ <=> __y.__current_;
}
#else // ^^^ _LIBCUDACXX_HAS_NO_SPACESHIP_OPERATOR ^^^ / vvv !_LIBCUDACXX_HAS_NO_SPACESHIP_OPERATOR vvv
//! @brief Compares two @c shuffle_iterator for less than by comparing their index
[[nodiscard]] _CCCL_API friend constexpr bool
operator<(const shuffle_iterator& __x, const shuffle_iterator& __y) noexcept
{
return __x.__current_ < __y.__current_;
}
//! @brief Compares two @c shuffle_iterator for greater than by comparing their index
[[nodiscard]] _CCCL_API friend constexpr bool
operator>(const shuffle_iterator& __x, const shuffle_iterator& __y) noexcept
{
return __x.__current_ > __y.__current_;
}
//! @brief Compares two @c shuffle_iterator for less equal by comparing their index
[[nodiscard]] _CCCL_API friend constexpr bool
operator<=(const shuffle_iterator& __x, const shuffle_iterator& __y) noexcept
{
return __x.__current_ <= __y.__current_;
}
//! @brief Compares two @c shuffle_iterator for greater equal by comparing their index
[[nodiscard]] _CCCL_API friend constexpr bool
operator>=(const shuffle_iterator& __x, const shuffle_iterator& __y) noexcept
{
return __x.__current_ >= __y.__current_;
}
#endif // !_LIBCUDACXX_HAS_NO_SPACESHIP_OPERATOR
};
_CCCL_TEMPLATE(class _Bijection)
_CCCL_REQUIRES(__is_bijection<_Bijection>)
_CCCL_DEDUCTION_GUIDE_ATTRIBUTES shuffle_iterator(_Bijection)
-> shuffle_iterator<typename _Bijection::index_type, _Bijection>;
_CCCL_TEMPLATE(class _Bijection, typename _Integral)
_CCCL_REQUIRES(__is_bijection<_Bijection> _CCCL_AND ::cuda::std::is_integral_v<_Integral>)
_CCCL_DEDUCTION_GUIDE_ATTRIBUTES shuffle_iterator(_Bijection, _Integral)
-> shuffle_iterator<typename _Bijection::index_type, _Bijection>;
//! @brief make_shuffle_iterator creates a @c shuffle_iterator from an integer and a bijection function
//! @param __fun The bijection function used for shuffling
//! @param __start The starting position of the @c shuffle_iterator
//! @relates shuffle_iterator
template <class _Bijection, class _IndexType>
[[nodiscard]] _CCCL_API constexpr auto make_shuffle_iterator(_Bijection __fun, _IndexType __start = 0)
{
return shuffle_iterator<_IndexType, _Bijection>{::cuda::std::move(__fun), __start};
}
//! @}
_CCCL_END_NV_DIAG_SUPPRESS()
_CCCL_END_NAMESPACE_CUDA
#include <cuda/std/__cccl/epilogue.h>
#endif // _CUDA___ITERATOR_TRANSFORM_ITERATOR_H

View File

@@ -0,0 +1,435 @@
//===----------------------------------------------------------------------===//
//
// 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___ITERATOR_STRIDED_ITERATOR_H
#define _CUDA___ITERATOR_STRIDED_ITERATOR_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/__fwd/iterator.h>
#if _LIBCUDACXX_HAS_SPACESHIP_OPERATOR()
# include <cuda/std/__compare/three_way_comparable.h>
#endif // _LIBCUDACXX_HAS_SPACESHIP_OPERATOR()
#include <cuda/std/__concepts/constructible.h>
#include <cuda/std/__concepts/equality_comparable.h>
#include <cuda/std/__concepts/totally_ordered.h>
#include <cuda/std/__iterator/iterator_traits.h>
#include <cuda/std/__mdspan/submdspan_helper.h>
#include <cuda/std/__ranges/compressed_movable_box.h>
#include <cuda/std/__type_traits/is_nothrow_copy_constructible.h>
#include <cuda/std/__type_traits/is_nothrow_default_constructible.h>
#include <cuda/std/__type_traits/is_nothrow_move_constructible.h>
#include <cuda/std/__utility/declval.h>
#include <cuda/std/__utility/move.h>
#include <cuda/std/__cccl/prologue.h>
_CCCL_BEGIN_NAMESPACE_CUDA
//! @addtogroup iterators
//! @{
//! @brief A @c strided_iterator wraps another iterator and advances it by a specified stride each time it is
//! incremented or decremented.
//!
//! @tparam _Iter A random access iterator
//! @tparam _Stride Either an <a href="https://eel.is/c++draft/iterator.concept.winc#4">integer-like</a> or an
//! <a href="https://eel.is/c++draft/views.contiguous#concept:integral-constant-like">integral-constant-like</a>
//! specifying the stride
template <class _Iter, class _Stride>
class strided_iterator
{
private:
static_assert(::cuda::std::__has_random_access_traversal<_Iter>,
"The iterator underlying a strided_iterator must be a random access iterator.");
static_assert(::cuda::std::__integer_like<_Stride> || ::cuda::std::__integral_constant_like<_Stride>,
"The stride of a strided_iterator must either be an integer-like or integral-constant-like.");
template <class, class>
friend class strided_iterator;
// Not a base because then the friend operators would be ambiguous
::cuda::std::__compressed_movable_box<_Iter, _Stride> __store_;
[[nodiscard]] _CCCL_API constexpr _Iter& __iter() noexcept
{
return __store_.template __get<0>();
}
[[nodiscard]] _CCCL_API constexpr const _Iter& __iter() const noexcept
{
return __store_.template __get<0>();
}
[[nodiscard]] _CCCL_API constexpr _Stride& __stride() noexcept
{
return __store_.template __get<1>();
}
[[nodiscard]] _CCCL_API constexpr const _Stride& __stride() const noexcept
{
return __store_.template __get<1>();
}
public:
using iterator_concept = ::cuda::std::random_access_iterator_tag;
using iterator_category = ::cuda::std::random_access_iterator_tag;
using value_type = ::cuda::std::iter_value_t<_Iter>;
using difference_type = ::cuda::std::iter_difference_t<_Iter>;
// Those are technically not to spec, but pre-ranges iterator_traits do not work properly with iterators that do not
// define all 5 aliases, see https://en.cppreference.com/w/cpp/iterator/iterator_traits.html
using reference = ::cuda::std::iter_reference_t<_Iter>;
using pointer = void;
//! @brief value-initializes both the base iterator and stride
//! @note _Iter must be default initializable because it is a random_access_iterator and thereby semiregular
//! _Stride must be integer-like or integral_constant_like which requires default constructability
_CCCL_EXEC_CHECK_DISABLE
_CCCL_TEMPLATE(class _Iter2 = _Iter, class _Stride2 = _Stride)
_CCCL_REQUIRES(::cuda::std::default_initializable<_Iter2> _CCCL_AND ::cuda::std::default_initializable<_Stride2>)
_CCCL_API constexpr strided_iterator() noexcept(::cuda::std::is_nothrow_default_constructible_v<_Iter2>
&& ::cuda::std::is_nothrow_default_constructible_v<_Stride2>)
: __store_()
{}
//! @brief Constructs a @c strided_iterator from a base iterator
//! @param __iter The base iterator
//! @note We cannot construct a @c strided_iterator with an
//! <a href="https://eel.is/c++draft/iterator.concept.winc#4">integer-like</a> stride, because that would value
//! construct to 0 and incrementing the iterator would do nothing.
_CCCL_EXEC_CHECK_DISABLE
_CCCL_TEMPLATE(class _Stride2 = _Stride)
_CCCL_REQUIRES(::cuda::std::__integral_constant_like<_Stride2>)
_CCCL_API constexpr explicit strided_iterator(_Iter __iter) noexcept(
::cuda::std::is_nothrow_move_constructible_v<_Iter> && ::cuda::std::is_nothrow_default_constructible_v<_Stride2>)
: __store_(::cuda::std::move(__iter))
{}
//! @brief Constructs a @c strided_iterator from a base iterator and a stride
//! @param __iter The base iterator
//! @param __stride The new stride
_CCCL_EXEC_CHECK_DISABLE
_CCCL_API constexpr explicit strided_iterator(_Iter __iter, _Stride __stride) noexcept(
::cuda::std::is_nothrow_move_constructible_v<_Iter> && ::cuda::std::is_nothrow_move_constructible_v<_Stride>)
: __store_(::cuda::std::move(__iter), ::cuda::std::move(__stride))
{}
//! @brief Returns a const reference to the stored iterator
[[nodiscard]] _CCCL_API constexpr const _Iter& base() const& noexcept
{
return __iter();
}
//! @brief Extracts the stored iterator
_CCCL_EXEC_CHECK_DISABLE
[[nodiscard]] _CCCL_API constexpr _Iter base() && noexcept(::cuda::std::is_nothrow_move_constructible_v<_Iter>)
{
return ::cuda::std::move(__iter());
}
static constexpr bool __noexcept_stride =
noexcept(static_cast<difference_type>(::cuda::std::__de_ice(::cuda::std::declval<const _Stride&>())));
//! @brief Returns the current stride as an integral value
_CCCL_EXEC_CHECK_DISABLE
[[nodiscard]] _CCCL_API constexpr difference_type stride() const noexcept(__noexcept_stride)
{
return static_cast<difference_type>(::cuda::std::__de_ice(__stride()));
}
//! @brief Dereferences the stored base iterator
_CCCL_EXEC_CHECK_DISABLE
[[nodiscard]] _CCCL_API constexpr decltype(auto) operator*() noexcept(noexcept(*::cuda::std::declval<_Iter&>()))
{
return *__iter();
}
//! @brief Dereferences the stored base iterator
_CCCL_EXEC_CHECK_DISABLE
_CCCL_TEMPLATE(class _Iter2 = _Iter)
_CCCL_REQUIRES(::cuda::std::__dereferenceable<const _Iter2>)
[[nodiscard]] _CCCL_API constexpr decltype(auto) operator*() const
noexcept(noexcept(*::cuda::std::declval<const _Iter2&>()))
{
return *__iter();
}
//! @brief Subscripts the stored base iterator with a given offset times the stride
//! @param __n The offset
_CCCL_EXEC_CHECK_DISABLE
[[nodiscard]] _CCCL_API constexpr decltype(auto)
operator[](difference_type __n) noexcept(__noexcept_stride && noexcept(::cuda::std::declval<_Iter&>()[__n]))
{
return __iter()[__n * stride()];
}
//! @brief Subscripts the stored base iterator with a given offset times the stride
//! @param __n The offset
_CCCL_EXEC_CHECK_DISABLE
_CCCL_TEMPLATE(class _Iter2 = _Iter)
_CCCL_REQUIRES(::cuda::std::__dereferenceable<const _Iter2>)
[[nodiscard]] _CCCL_API constexpr decltype(auto) operator[](difference_type __n) const
noexcept(__noexcept_stride && noexcept(::cuda::std::declval<const _Iter2&>()[__n]))
{
return __iter()[__n * stride()];
}
//! @brief Increments the stored base iterator by the stride
// Note: we cannot use __iter() += stride() in the noexcept clause because that breaks gcc < 9
_CCCL_EXEC_CHECK_DISABLE
_CCCL_API constexpr strided_iterator&
operator++() noexcept(__noexcept_stride && noexcept(::cuda::std::declval<_Iter&>() += 1))
{
__iter() += stride();
return *this;
}
//! @brief Increments the stored base iterator by the stride
_CCCL_EXEC_CHECK_DISABLE
_CCCL_API constexpr auto operator++(int) noexcept(
noexcept(__noexcept_stride && noexcept(::cuda::std::declval<_Iter&>() += 1))
&& ::cuda::std::is_nothrow_copy_constructible_v<_Iter> && ::cuda::std::is_nothrow_copy_constructible_v<_Stride>)
{
auto __tmp = *this;
__iter() += stride();
return __tmp;
}
//! @brief Decrements the stored base iterator by the stride
_CCCL_EXEC_CHECK_DISABLE
_CCCL_API constexpr strided_iterator&
operator--() noexcept(__noexcept_stride && noexcept(::cuda::std::declval<_Iter&>() -= 1))
{
__iter() -= stride();
return *this;
}
//! @brief Decrements the stored base iterator by the stride
_CCCL_EXEC_CHECK_DISABLE
_CCCL_API constexpr strided_iterator operator--(int) noexcept(
noexcept(__noexcept_stride && noexcept(::cuda::std::declval<_Iter&>() -= 1))
&& ::cuda::std::is_nothrow_copy_constructible_v<_Iter> && ::cuda::std::is_nothrow_copy_constructible_v<_Stride>)
{
auto __tmp = *this;
__iter() -= stride();
return __tmp;
}
//! @brief Advances a @c strided_iterator by a given number of steps
//! @param __n The number of steps to increment
//! @note Increments the base iterator by @c __n times the stride
_CCCL_EXEC_CHECK_DISABLE
_CCCL_API constexpr strided_iterator&
operator+=(difference_type __n) noexcept(__noexcept_stride && noexcept(::cuda::std::declval<_Iter&>() += 1))
{
__iter() += stride() * __n;
return *this;
}
template <class _Iter2>
static constexpr bool __nothrow_plus =
::cuda::std::is_nothrow_copy_constructible_v<_Iter2>
&& noexcept(::cuda::std::declval<const _Iter2&>() + difference_type());
//! @brief Returns a copy of a @c strided_iterator incremented by a given number of steps
//! @param __iter The @c strided_iterator to advance
//! @param __n The number of steps to increment
_CCCL_EXEC_CHECK_DISABLE
template <int = 0> // Must be template, or the compiler complains about a nonliteral return type
[[nodiscard]]
_CCCL_API friend constexpr strided_iterator
operator+(const strided_iterator& __iter, difference_type __n) noexcept(__nothrow_plus<_Iter>)
{
return strided_iterator{__iter.__iter() + __iter.stride() * __n, __iter.__stride()};
}
//! @brief Returns a copy of a @c strided_iterator incremented by a given number of steps
//! @param __n The number of steps to increment
//! @param __iter The @c strided_iterator to advance
_CCCL_EXEC_CHECK_DISABLE
template <int = 0> // Must be template, or the compiler complains about a nonliteral return type
[[nodiscard]]
_CCCL_API friend constexpr strided_iterator
operator+(difference_type __n, const strided_iterator& __iter) noexcept(__nothrow_plus<_Iter>)
{
return strided_iterator{__iter.__iter() + __iter.stride() * __n, __iter.__stride()};
}
//! @brief Decrements a @c strided_iterator by a given number of steps
//! @param __n The number of steps to decrement
//! @note Decrements the base iterator by @c __n times the stride
_CCCL_EXEC_CHECK_DISABLE
_CCCL_API constexpr strided_iterator&
operator-=(difference_type __n) noexcept(__noexcept_stride && noexcept(::cuda::std::declval<_Iter&>() -= 1))
{
__iter() -= stride() * __n;
return *this;
}
template <class _Iter2>
static constexpr bool __nothrow_minus =
::cuda::std::is_nothrow_copy_constructible_v<_Iter2>
&& noexcept(::cuda::std::declval<const _Iter2&>() - difference_type());
//! @brief Returns a copy of a @c strided_iterator decremented by a given number of steps
//! @param __n The number of steps to decrement
//! @param __iter The @c strided_iterator to decrement
_CCCL_EXEC_CHECK_DISABLE
template <int = 0> // Must be template, or the compiler complains about a nonliteral return type
[[nodiscard]]
_CCCL_API friend constexpr strided_iterator
operator-(const strided_iterator& __iter, difference_type __n) noexcept(__nothrow_minus<_Iter>)
{
return strided_iterator{__iter.__iter() - __iter.stride() * __n, __iter.__stride()};
}
template <class _Iter2, class _OtherIter>
static constexpr bool __noexcept_difference =
noexcept(::cuda::std::declval<const _Iter2&>() - ::cuda::std::declval<const _OtherIter&>());
//! @brief Returns distance between two @c strided_iterator's in units of the stride
_CCCL_EXEC_CHECK_DISABLE
_CCCL_TEMPLATE(class _OtherIter, class _OtherStride)
_CCCL_REQUIRES(::cuda::std::sized_sentinel_for<_OtherIter, _Iter>)
[[nodiscard]] _CCCL_API friend constexpr difference_type
operator-(const strided_iterator& __x, const strided_iterator<_OtherIter, _OtherStride>& __y) //
noexcept(__noexcept_difference<_Iter, _OtherIter>)
{
const difference_type __diff = __x.__iter() - __y.base();
_CCCL_ASSERT(__x.stride() == __y.stride(), "Taking the difference of two strided_iterators with different stride");
_CCCL_ASSERT(__diff % __x.stride() == 0, "Underlying iterator difference must be divisible by the stride");
return __diff / __x.stride();
}
//! @brief Compares two @c strided_iterator's for equality by comparing the stored iterators
_CCCL_EXEC_CHECK_DISABLE
_CCCL_TEMPLATE(class _OtherIter, class _OtherStride)
_CCCL_REQUIRES(::cuda::std::equality_comparable_with<_Iter, _OtherIter>)
[[nodiscard]] _CCCL_API friend constexpr bool
operator==(const strided_iterator& __x, const strided_iterator<_OtherIter, _OtherStride>& __y) noexcept(
noexcept(::cuda::std::declval<const _Iter&>() == ::cuda::std::declval<const _OtherIter&>()))
{
return __x.__iter() == __y.base();
}
#if _CCCL_STD_VER <= 2017
//! @brief Compares two @c strided_iterator's for inequality by comparing the stored iterators
_CCCL_EXEC_CHECK_DISABLE
_CCCL_TEMPLATE(class _OtherIter, class _OtherStride)
_CCCL_REQUIRES(::cuda::std::equality_comparable_with<_Iter, _OtherIter>)
[[nodiscard]] _CCCL_API friend constexpr bool
operator!=(const strided_iterator& __x, const strided_iterator<_OtherIter, _OtherStride>& __y) noexcept(
noexcept(::cuda::std::declval<const _Iter&>() == ::cuda::std::declval<const _OtherIter&>()))
{
return __x.__iter() != __y.base();
}
#endif // _CCCL_STD_VER <= 2017
#if _LIBCUDACXX_HAS_SPACESHIP_OPERATOR()
//! @brief Threeway-compares two @c strided_iterator's by comparing the stored iterators
_CCCL_TEMPLATE(class _OtherIter, class _OtherStride)
_CCCL_REQUIRES(::cuda::std::totally_ordered_with<_Iter, _OtherIter>)
_CCCL_REQUIRES(
::cuda::std::totally_ordered<_Iter, _OtherIter> _CCCL_AND ::cuda::std::three_way_comparable_with<_Iter, _OtherIter>)
[[nodiscard]] _CCCL_API friend constexpr auto
operator<=>(const strided_iterator& __x, const strided_iterator<_OtherIter, _OtherStride>& __y) noexcept(
noexcept(::cuda::std::declval<const _Iter&>() <=> ::cuda::std::declval<const _OtherIter&>()))
{
return __x.__iter() <=> __y.base();
}
#else // ^^^ _LIBCUDACXX_HAS_SPACESHIP_OPERATOR() ^^^ / vvv !_LIBCUDACXX_HAS_SPACESHIP_OPERATOR() vvv
//! @brief Compares two @c strided_iterator's for less than by comparing the stored iterators
_CCCL_EXEC_CHECK_DISABLE
_CCCL_TEMPLATE(class _OtherIter, class _OtherStride)
_CCCL_REQUIRES(::cuda::std::totally_ordered_with<_Iter, _OtherIter>)
[[nodiscard]] _CCCL_API friend constexpr bool
operator<(const strided_iterator& __x, const strided_iterator<_OtherIter, _OtherStride>& __y) noexcept(
noexcept(::cuda::std::declval<const _Iter&>() < ::cuda::std::declval<const _OtherIter&>()))
{
return __x.__iter() < __y.base();
}
//! @brief Compares two @c strided_iterator's for greater than by comparing the stored iterators
_CCCL_EXEC_CHECK_DISABLE
_CCCL_TEMPLATE(class _OtherIter, class _OtherStride)
_CCCL_REQUIRES(::cuda::std::totally_ordered_with<_Iter, _OtherIter>)
[[nodiscard]] _CCCL_API friend constexpr bool
operator>(const strided_iterator& __x, const strided_iterator<_OtherIter, _OtherStride>& __y) noexcept(
noexcept(::cuda::std::declval<const _Iter&>() < ::cuda::std::declval<const _OtherIter&>()))
{
return __y < __x;
}
//! @brief Compares two @c strided_iterator's for less equal by comparing the stored iterators
_CCCL_EXEC_CHECK_DISABLE
_CCCL_TEMPLATE(class _OtherIter, class _OtherStride)
_CCCL_REQUIRES(::cuda::std::totally_ordered_with<_Iter, _OtherIter>)
[[nodiscard]] _CCCL_API friend constexpr bool
operator<=(const strided_iterator& __x, const strided_iterator<_OtherIter, _OtherStride>& __y) noexcept(
noexcept(::cuda::std::declval<const _Iter&>() < ::cuda::std::declval<const _OtherIter&>()))
{
return !(__y < __x);
}
//! @brief Compares two @c strided_iterator's for greater equal by comparing the stored iterators
_CCCL_EXEC_CHECK_DISABLE
_CCCL_TEMPLATE(class _OtherIter, class _OtherStride)
_CCCL_REQUIRES(::cuda::std::totally_ordered_with<_Iter, _OtherIter>)
[[nodiscard]] _CCCL_API friend constexpr bool
operator>=(const strided_iterator& __x, const strided_iterator<_OtherIter, _OtherStride>& __y) noexcept(
noexcept(::cuda::std::declval<const _Iter&>() < ::cuda::std::declval<const _OtherIter&>()))
{
return !(__x < __y);
}
#endif // !_LIBCUDACXX_HAS_SPACESHIP_OPERATOR()
};
#ifndef _CCCL_DOXYGEN_INVOKED
template <class _Iter, typename _Stride>
_CCCL_DEDUCTION_GUIDE_ATTRIBUTES strided_iterator(_Iter, _Stride) -> strided_iterator<_Iter, _Stride>;
#endif // _CCCL_DOXYGEN_INVOKED
//! @brief Creates a @c strided_iterator from a random access iterator
//! @param __iter The random_access iterator
//! @relates strided_iterator
_CCCL_TEMPLATE(class _Stride, class _Iter)
_CCCL_REQUIRES(::cuda::std::__integral_constant_like<_Stride>)
[[nodiscard]] _CCCL_API constexpr auto make_strided_iterator(_Iter __iter)
{
return strided_iterator<_Iter, _Stride>{::cuda::std::move(__iter)};
}
//! @brief Creates a @c strided_iterator from a random access iterator and a stride
//! @param __iter The random_access iterator
//! @param __stride The new stride
//! @relates strided_iterator
template <class _Iter, class _Stride>
[[nodiscard]] _CCCL_API constexpr auto make_strided_iterator(_Iter __iter, _Stride __stride)
{
return strided_iterator<_Iter, _Stride>{::cuda::std::move(__iter), __stride};
}
//! @} // end iterators
_CCCL_END_NAMESPACE_CUDA
#include <cuda/std/__cccl/epilogue.h>
#endif // _CUDA___ITERATOR_STRIDED_ITERATOR_H

View File

@@ -0,0 +1,381 @@
//===----------------------------------------------------------------------===//
//
// 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___ITERATOR_TABULATE_OUTPUT_ITERATOR_H
#define _CUDA___ITERATOR_TABULATE_OUTPUT_ITERATOR_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/__fwd/iterator.h>
#include <cuda/std/__concepts/constructible.h>
#include <cuda/std/__functional/invoke.h>
#include <cuda/std/__iterator/concepts.h>
#include <cuda/std/__iterator/iterator_traits.h>
#include <cuda/std/__ranges/compressed_movable_box.h>
#include <cuda/std/__ranges/movable_box.h>
#include <cuda/std/__type_traits/conditional.h>
#include <cuda/std/__type_traits/is_nothrow_copy_constructible.h>
#include <cuda/std/__type_traits/is_nothrow_default_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/remove_cvref.h>
#include <cuda/std/__utility/forward.h>
#include <cuda/std/__utility/move.h>
#include <cuda/std/cstdint>
#include <cuda/std/__cccl/prologue.h>
_CCCL_BEGIN_NAMESPACE_CUDA
//! @addtogroup iterators
//! @{
template <class _Fn, class _Index>
class __tabulate_proxy
{
private:
template <class, class>
friend class tabulate_output_iterator;
_Fn& __func_;
_Index __index_;
_CCCL_API constexpr explicit __tabulate_proxy(_Fn& __func, _Index __index) noexcept
: __func_(__func)
, __index_(__index)
{}
public:
_CCCL_HIDE_FROM_ABI __tabulate_proxy(const __tabulate_proxy&) = default;
_CCCL_HIDE_FROM_ABI __tabulate_proxy& operator=(const __tabulate_proxy&) = default;
_CCCL_HIDE_FROM_ABI __tabulate_proxy(__tabulate_proxy&&) = default;
_CCCL_HIDE_FROM_ABI __tabulate_proxy& operator=(__tabulate_proxy&&) = default;
_CCCL_TEMPLATE(class _Arg)
_CCCL_REQUIRES(::cuda::std::is_invocable_v<_Fn&, _Index, _Arg>)
_CCCL_API constexpr const __tabulate_proxy&
operator=(_Arg&& __arg) noexcept(::cuda::std::is_nothrow_invocable_v<_Fn&, _Index, _Arg>)
{
::cuda::std::invoke(__func_, __index_, ::cuda::std::forward<_Arg>(__arg));
return *this;
}
_CCCL_TEMPLATE(class _Arg)
_CCCL_REQUIRES(::cuda::std::is_invocable_v<const _Fn&, _Index, _Arg>)
_CCCL_API constexpr const __tabulate_proxy& operator=(_Arg&& __arg) const
noexcept(::cuda::std::is_nothrow_invocable_v<const _Fn&, _Index, _Arg>)
{
::cuda::std::invoke(__func_, __index_, ::cuda::std::forward<_Arg>(__arg));
return *this;
}
};
//! @brief @c tabulate_output_iterator is a special kind of output iterator which, whenever a value is assigned to a
//! dereferenced iterator, calls the given callable with the index that corresponds to the offset of the dereferenced
//! iterator and the assigned value.
//!
//! The following code snippet demonstrates how to create a @c tabulate_output_iterator which prints the index and the
//! assigned value.
//!
//! @code
//! #include <cuda/iterator>
//!
//! struct print_op
//! {
//! __host__ __device__ void operator()(int index, float value) const
//! {
//! printf("%d: %f\n", index, value);
//! }
//! };
//!
//! int main()
//! {
//! auto tabulate_it = cuda::make_tabulate_output_iterator(print_op{});
//!
//! tabulate_it[0] = 1.0f; // prints: 0: 1.0
//! tabulate_it[1] = 3.0f; // prints: 1: 3.0
//! tabulate_it[9] = 5.0f; // prints: 9: 5.0
//! }
//! @endcode
template <class _Fn, class _Index>
class tabulate_output_iterator
{
private:
// Not a base because then the friend operators would be ambiguous
::cuda::std::__compressed_movable_box<_Index, _Fn> __store_;
[[nodiscard]] _CCCL_API constexpr _Index& __index() noexcept
{
return __store_.template __get<0>();
}
[[nodiscard]] _CCCL_API constexpr const _Index& __index() const noexcept
{
return __store_.template __get<0>();
}
[[nodiscard]] _CCCL_API constexpr _Fn& __func() noexcept
{
return __store_.template __get<1>();
}
[[nodiscard]] _CCCL_API constexpr const _Fn& __func() const noexcept
{
return __store_.template __get<1>();
}
static_assert(::cuda::std::is_signed_v<_Index>, "tabulate_output_iterator: _Index must be a signed integer");
public:
using iterator_concept = ::cuda::std::random_access_iterator_tag;
using iterator_category = ::cuda::std::random_access_iterator_tag;
using difference_type = _Index;
using value_type = void;
using pointer = void;
using reference = void;
_CCCL_EXEC_CHECK_DISABLE
_CCCL_TEMPLATE(class _Fn2 = _Fn)
_CCCL_REQUIRES(::cuda::std::default_initializable<_Fn2>)
_CCCL_API constexpr tabulate_output_iterator() noexcept(::cuda::std::is_nothrow_default_constructible_v<_Fn2>)
: __store_()
{}
//! @brief Constructs a @c tabulate_output_iterator with a given functor and an optional index
//! @param __func the output function
//! @param __index the position in the output sequence
_CCCL_EXEC_CHECK_DISABLE
_CCCL_API constexpr tabulate_output_iterator(_Fn __func, _Index __index = 0) noexcept(
::cuda::std::is_nothrow_move_constructible_v<_Fn>)
: __store_(__index, ::cuda::std::move(__func))
{}
//! @brief Returns the stored index
[[nodiscard]] _CCCL_API constexpr difference_type index() const noexcept
{
return __index();
}
//! @brief Dereferences the @c tabulate_output_iterator
//! @returns A proxy that applies the stored function and index on assignment
[[nodiscard]] _CCCL_API constexpr auto operator*() const noexcept
{
return __tabulate_proxy<_Fn, _Index>{const_cast<_Fn&>(__func()), __index()};
}
//! @brief Dereferences the @c tabulate_output_iterator
//! @returns A proxy that applies the stored function and index on assignment
[[nodiscard]] _CCCL_API constexpr auto operator*() noexcept
{
return __tabulate_proxy<_Fn, _Index>{__func(), __index()};
}
//! @brief Subscripts the @c tabulate_output_iterator with a given offset
//! @param __n The additional offset to advance the stored index
//! @returns A proxy that applies the stored function and index on assignment
[[nodiscard]] _CCCL_API constexpr auto operator[](difference_type __n) const noexcept
{
return __tabulate_proxy<_Fn, _Index>{const_cast<_Fn&>(__func()), static_cast<difference_type>(__index() + __n)};
}
//! @brief Subscripts the @c tabulate_output_iterator with a given offset
//! @param __n The additional offset to advance the stored index
//! @returns A proxy that applies the stored function and index on assignment
[[nodiscard]] _CCCL_API constexpr auto operator[](difference_type __n) noexcept
{
return __tabulate_proxy<_Fn, _Index>{__func(), static_cast<difference_type>(__index() + __n)};
}
//! @brief Increments the @c tabulate_output_iterator by incrementing the stored index
_CCCL_EXEC_CHECK_DISABLE
_CCCL_API constexpr tabulate_output_iterator& operator++() noexcept
{
++__index();
return *this;
}
//! @brief Increments the @c tabulate_output_iterator by incrementing the stored index
_CCCL_EXEC_CHECK_DISABLE
_CCCL_API constexpr tabulate_output_iterator
operator++(int) noexcept(::cuda::std::is_nothrow_copy_constructible_v<_Fn>)
{
tabulate_output_iterator __tmp = *this;
++__index();
return __tmp;
}
//! @brief Decrements the @c tabulate_output_iterator by decrementing the stored index
_CCCL_EXEC_CHECK_DISABLE
_CCCL_API constexpr tabulate_output_iterator& operator--() noexcept
{
--__index();
return *this;
}
//! @brief Decrements the @c tabulate_output_iterator by decrementing the stored index
_CCCL_EXEC_CHECK_DISABLE
_CCCL_API constexpr tabulate_output_iterator
operator--(int) noexcept(::cuda::std::is_nothrow_copy_constructible_v<_Fn>)
{
tabulate_output_iterator __tmp = *this;
--__index();
return __tmp;
}
//! @brief Returns a copy of this @c tabulate_output_iterator advanced a given number of elements
//! @param __n The number of elements to advance
_CCCL_EXEC_CHECK_DISABLE
template <int = 0> // Template because compiler will complain about non-literal return type if _Fn is not a literal
[[nodiscard]] _CCCL_API friend constexpr tabulate_output_iterator
operator+(const tabulate_output_iterator& __iter, difference_type __n) //
noexcept(::cuda::std::is_nothrow_copy_constructible_v<_Fn>)
{
return tabulate_output_iterator{__iter.__func(), static_cast<difference_type>(__iter.__index() + __n)};
}
//! @brief Returns a copy of a @c tabulate_output_iterator advanced a given number of elements
//! @param __n The number of elements to advance
//! @param __iter The original @c tabulate_output_iterator
_CCCL_EXEC_CHECK_DISABLE
template <int = 0> // Template because compiler will complain about non-literal return type if _Fn is not a literal
[[nodiscard]] _CCCL_API friend constexpr tabulate_output_iterator
operator+(difference_type __n, const tabulate_output_iterator& __iter) //
noexcept(::cuda::std::is_nothrow_copy_constructible_v<_Fn>)
{
return tabulate_output_iterator{__iter.__func(), static_cast<difference_type>(__iter.__index() + __n)};
}
//! @brief Advances the @c tabulate_output_iterator by a given number of elements
//! @param __n The number of elements to advance
_CCCL_EXEC_CHECK_DISABLE
_CCCL_API constexpr tabulate_output_iterator& operator+=(difference_type __n) noexcept
{
__index() += __n;
return *this;
}
//! @brief Returns a copy of this @c tabulate_output_iterator decremented a given number of elements
//! @param __n The number of elements to decremented
_CCCL_EXEC_CHECK_DISABLE
template <int = 0> // Template because compiler will complain about non-literal return type if _Fn is not a literal
[[nodiscard]] _CCCL_API friend constexpr tabulate_output_iterator
operator-(const tabulate_output_iterator& __iter, difference_type __n) //
noexcept(::cuda::std::is_nothrow_copy_constructible_v<_Fn>)
{
return tabulate_output_iterator{__iter.__func(), static_cast<difference_type>(__iter.__index() - __n)};
}
//! @brief Returns the distance between two @c tabulate_output_iterator 's
[[nodiscard]] _CCCL_API friend constexpr difference_type
operator-(const tabulate_output_iterator& __lhs, const tabulate_output_iterator& __rhs) noexcept
{
return __lhs.__index() - __rhs.__index();
}
//! @brief Decrements the @c tabulate_output_iterator by a given number of elements
//! @param __n The number of elements to decrement
_CCCL_EXEC_CHECK_DISABLE
_CCCL_API constexpr tabulate_output_iterator& operator-=(difference_type __n) noexcept
{
__index() -= __n;
return *this;
}
//! @brief Compares two @c tabulate_output_iterator for equality by comparing their indices
[[nodiscard]] _CCCL_API friend constexpr bool
operator==(const tabulate_output_iterator& __lhs, const tabulate_output_iterator& __rhs) noexcept
{
return __lhs.__index() == __rhs.__index();
}
#if _CCCL_STD_VER <= 2017
//! @brief Compares two @c tabulate_output_iterator for inequality by comparing their indices
[[nodiscard]] _CCCL_API friend constexpr bool
operator!=(const tabulate_output_iterator& __lhs, const tabulate_output_iterator& __rhs) noexcept
{
return __lhs.__index() != __rhs.__index();
}
#endif // _CCCL_STD_VER <= 2017
#if _LIBCUDACXX_HAS_SPACESHIP_OPERATOR()
//! @brief Three-way-compares two @c tabulate_output_iterator by comparing their indices
[[nodiscard]] _CCCL_API friend constexpr strong_ordering
operator<=>(const tabulate_output_iterator& __lhs, const tabulate_output_iterator& __rhs) noexcept
{
return __lhs.__index() <=> __rhs.__index();
}
#else // ^^^ _LIBCUDACXX_HAS_SPACESHIP_OPERATOR() ^^^ / vvv !_LIBCUDACXX_HAS_SPACESHIP_OPERATOR() vvv
//! @brief Compares two @c tabulate_output_iterator for less than by comparing their indices
[[nodiscard]] _CCCL_API friend constexpr bool
operator<(const tabulate_output_iterator& __lhs, const tabulate_output_iterator& __rhs) noexcept
{
return __lhs.__index() < __rhs.__index();
}
//! @brief Compares two @c tabulate_output_iterator for less equal by comparing their indices
[[nodiscard]] _CCCL_API friend constexpr bool
operator<=(const tabulate_output_iterator& __lhs, const tabulate_output_iterator& __rhs) noexcept
{
return __lhs.__index() <= __rhs.__index();
}
//! @brief Compares two @c tabulate_output_iterator for greater than by comparing their indices
[[nodiscard]] _CCCL_API friend constexpr bool
operator>(const tabulate_output_iterator& __lhs, const tabulate_output_iterator& __rhs) noexcept
{
return __lhs.__index() > __rhs.__index();
}
//! @brief Compares two @c tabulate_output_iterator for greater equal by comparing their indices
[[nodiscard]] _CCCL_API friend constexpr bool
operator>=(const tabulate_output_iterator& __lhs, const tabulate_output_iterator& __rhs) noexcept
{
return __lhs.__index() >= __rhs.__index();
}
#endif // !_LIBCUDACXX_HAS_SPACESHIP_OPERATOR()
};
#ifndef _CCCL_DOXYGEN_INVOKED
template <class _Fn>
_CCCL_DEDUCTION_GUIDE_ATTRIBUTES tabulate_output_iterator(_Fn) -> tabulate_output_iterator<_Fn, ::cuda::std::ptrdiff_t>;
_CCCL_TEMPLATE(class _Fn, class _Index)
_CCCL_REQUIRES(::cuda::std::__integer_like<_Index>)
_CCCL_DEDUCTION_GUIDE_ATTRIBUTES tabulate_output_iterator(_Fn, _Index) -> tabulate_output_iterator<_Fn, _Index>;
#endif // _CCCL_DOXYGEN_INVOKED
//! @brief Creates a @c tabulate_output_iterator from an output function and an optional index.
//! @param __func The output function
//! @param __index The index of the @c tabulate_output_iterator within a range. The default index is @c 0.
//! @return A new @c tabulate_output_iterator with @c __index as the counter.
//! @relates tabulate_output_iterator
_CCCL_TEMPLATE(class _Fn, class _Integer = ::cuda::std::ptrdiff_t)
_CCCL_REQUIRES(::cuda::std::__integer_like<_Integer>)
[[nodiscard]] _CCCL_API constexpr auto make_tabulate_output_iterator(_Fn __func, _Integer __index = 0)
{
return tabulate_output_iterator{::cuda::std::move(__func), __index};
}
//! @}
_CCCL_END_NAMESPACE_CUDA
#include <cuda/std/__cccl/epilogue.h>
#endif // _CUDA___ITERATOR_TABULATE_OUTPUT_ITERATOR_H

View File

@@ -0,0 +1,580 @@
//===----------------------------------------------------------------------===//
//
// 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___ITERATOR_TRANSFORM_INPUT_OUTPUT_ITERATOR_H
#define _CUDA___ITERATOR_TRANSFORM_INPUT_OUTPUT_ITERATOR_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/__fwd/iterator.h>
#if _LIBCUDACXX_HAS_SPACESHIP_OPERATOR()
# include <cuda/std/__compare/three_way_comparable.h>
#endif // _LIBCUDACXX_HAS_SPACESHIP_OPERATOR()
#include <cuda/std/__concepts/constructible.h>
#include <cuda/std/__concepts/derived_from.h>
#include <cuda/std/__concepts/equality_comparable.h>
#include <cuda/std/__concepts/invocable.h>
#include <cuda/std/__functional/invoke.h>
#include <cuda/std/__iterator/advance.h>
#include <cuda/std/__iterator/concepts.h>
#include <cuda/std/__iterator/distance.h>
#include <cuda/std/__iterator/iterator_traits.h>
#include <cuda/std/__ranges/compressed_movable_box.h>
#include <cuda/std/__ranges/concepts.h>
#include <cuda/std/__ranges/movable_box.h>
#include <cuda/std/__type_traits/conditional.h>
#include <cuda/std/__type_traits/enable_if.h>
#include <cuda/std/__type_traits/is_assignable.h>
#include <cuda/std/__type_traits/is_nothrow_assignable.h>
#include <cuda/std/__type_traits/is_nothrow_default_constructible.h>
#include <cuda/std/__type_traits/is_nothrow_move_constructible.h>
#include <cuda/std/__type_traits/is_object.h>
#include <cuda/std/__type_traits/is_reference.h>
#include <cuda/std/__type_traits/remove_cvref.h>
#include <cuda/std/__utility/declval.h>
#include <cuda/std/__utility/forward.h>
#include <cuda/std/__utility/move.h>
#include <cuda/std/__cccl/prologue.h>
_CCCL_BEGIN_NAMESPACE_CUDA
template <class _InputFn, class _OutputFn, class _Iter>
class __transform_input_output_proxy
{
private:
template <class, class, class>
friend class transform_input_output_iterator;
_Iter __iter_;
_InputFn& __input_func_;
_OutputFn& __output_func_;
using _InputValueType = ::cuda::std::invoke_result_t<_InputFn, ::cuda::std::iter_value_t<_Iter>>;
_CCCL_EXEC_CHECK_DISABLE
_CCCL_API constexpr explicit __transform_input_output_proxy(
_Iter __iter,
_InputFn& __input_func,
_OutputFn& __output_func) noexcept(::cuda::std::is_nothrow_copy_constructible_v<_Iter>)
: __iter_(__iter)
, __input_func_(__input_func)
, __output_func_(__output_func)
{}
public:
_CCCL_HIDE_FROM_ABI __transform_input_output_proxy(const __transform_input_output_proxy&) = default;
_CCCL_HIDE_FROM_ABI __transform_input_output_proxy& operator=(const __transform_input_output_proxy&) = default;
_CCCL_HIDE_FROM_ABI __transform_input_output_proxy(__transform_input_output_proxy&&) = default;
_CCCL_HIDE_FROM_ABI __transform_input_output_proxy& operator=(__transform_input_output_proxy&&) = default;
_CCCL_EXEC_CHECK_DISABLE
_CCCL_TEMPLATE(class _Arg)
_CCCL_REQUIRES(::cuda::std::is_invocable_v<_OutputFn&, _Arg> //
_CCCL_AND ::cuda::std::is_assignable_v<::cuda::std::iter_reference_t<_Iter>,
::cuda::std::invoke_result_t<_OutputFn&, _Arg>>)
_CCCL_API constexpr __transform_input_output_proxy& operator=(_Arg&& __arg) noexcept(
noexcept(*__iter_ = ::cuda::std::invoke(__output_func_, ::cuda::std::forward<_Arg>(__arg))))
{
*__iter_ = ::cuda::std::invoke(__output_func_, ::cuda::std::forward<_Arg>(__arg));
return *this;
}
_CCCL_EXEC_CHECK_DISABLE
_CCCL_TEMPLATE(class _Arg)
_CCCL_REQUIRES(::cuda::std::is_invocable_v<const _OutputFn&, _Arg>
_CCCL_AND ::cuda::std::is_assignable_v<::cuda::std::iter_reference_t<const _Iter>,
::cuda::std::invoke_result_t<const _OutputFn&, _Arg>>)
_CCCL_API constexpr const __transform_input_output_proxy& operator=(_Arg&& __arg) const
noexcept(noexcept(*__iter_ = ::cuda::std::invoke(__output_func_, ::cuda::std::forward<_Arg>(__arg))))
{
*__iter_ = ::cuda::std::invoke(__output_func_, ::cuda::std::forward<_Arg>(__arg));
return *this;
}
_CCCL_EXEC_CHECK_DISABLE
_CCCL_API constexpr operator _InputValueType() const noexcept(noexcept(::cuda::std::invoke(__input_func_, *__iter_)))
{
return ::cuda::std::invoke(__input_func_, *__iter_);
}
};
//! @addtogroup iterators
//! @{
//! @brief @c transform_input_output_iterator is a special kind of iterator which applies transform functions when
//! reading from or writing to dereferenced values. This iterator is useful for algorithms that operate on a type that
//! needs to be serialized/deserialized from values in another iterator, avoiding the need to materialize intermediate
//! results in memory. This also enables the transform functions to be fused with the operations that read and write to
//! the `transform_input_output_iterator`.
//!
//! The following code snippet demonstrates how to create a @c transform_input_output_iterator which performs different
//! transformations when reading from and writing to the iterator.
//!
//! @code
//! #include <cuda/iterator>
//! #include <thrust/device_vector.h>
//!
//! int main()
//! {
//! const size_t size = 4;
//! thrust::device_vector<float> v(size);
//!
//! // Write 1.0f, 2.0f, 3.0f, 4.0f to vector
//! thrust::sequence(v.begin(), v.end(), 1);
//!
//! // Iterator that negates read values and writes squared values
//! auto iter = cuda::make_transform_input_output_iterator(v.begin(),
//! ::cuda::std::negate<float>{}, thrust::square<float>{});
//!
//! // Iterator negates values when reading
//! std::cout << iter[0] << " "; // -1.0f;
//! std::cout << iter[1] << " "; // -2.0f;
//! std::cout << iter[2] << " "; // -3.0f;
//! std::cout << iter[3] << "\n"; // -4.0f;
//!
//! // Write 1.0f, 2.0f, 3.0f, 4.0f to iterator
//! thrust::sequence(iter, iter + size, 1);
//!
//! // Values were squared before writing to vector
//! std::cout << v[0] << " "; // 1.0f;
//! std::cout << v[1] << " "; // 4.0f;
//! std::cout << v[2] << " "; // 9.0f;
//! std::cout << v[3] << "\n"; // 16.0f;
//!
//! }
//! @endcode
template <class _InputFn, class _OutputFn, class _Iter>
class transform_input_output_iterator
{
// Not a base because then the friend operators would be ambiguous
::cuda::std::__compressed_movable_box<_Iter, _InputFn, _OutputFn> __store_;
[[nodiscard]] _CCCL_API constexpr _Iter& __iter() noexcept
{
return __store_.template __get<0>();
}
[[nodiscard]] _CCCL_API constexpr const _Iter& __iter() const noexcept
{
return __store_.template __get<0>();
}
[[nodiscard]] _CCCL_API constexpr _InputFn& __input_func() noexcept
{
return __store_.template __get<1>();
}
[[nodiscard]] _CCCL_API constexpr const _InputFn& __input_func() const noexcept
{
return __store_.template __get<1>();
}
[[nodiscard]] _CCCL_API constexpr _OutputFn& __output_func() noexcept
{
return __store_.template __get<2>();
}
[[nodiscard]] _CCCL_API constexpr const _OutputFn& __output_func() const noexcept
{
return __store_.template __get<2>();
}
public:
using iterator_concept = ::cuda::std::conditional_t<
::cuda::std::__has_random_access_traversal<_Iter>,
::cuda::std::random_access_iterator_tag,
::cuda::std::conditional_t<::cuda::std::__has_bidirectional_traversal<_Iter>,
::cuda::std::bidirectional_iterator_tag,
::cuda::std::conditional_t<::cuda::std::__has_forward_traversal<_Iter>,
::cuda::std::forward_iterator_tag,
::cuda::std::output_iterator_tag>>>;
using iterator_category = ::cuda::std::output_iterator_tag;
using difference_type = ::cuda::std::iter_difference_t<_Iter>;
using value_type = ::cuda::std::invoke_result_t<_InputFn&, ::cuda::std::iter_reference_t<_Iter>>;
using pointer = void;
using reference = __transform_input_output_proxy<_InputFn, _OutputFn, _Iter>;
static_assert(::cuda::std::is_object_v<_InputFn>,
"cuda::transform_input_output_iterator requires that _InputFn is a function object");
static_assert(::cuda::std::is_object_v<_OutputFn>,
"cuda::transform_input_output_iterator requires that _OutputFn is a function object");
static_assert(::cuda::std::__has_forward_traversal<_Iter> || ::cuda::std::output_iterator<_Iter, value_type>,
"cuda::transform_input_output_iterator requires that _Iter models forward_iterator or output_iterator");
static_assert(::cuda::std::is_invocable_v<_InputFn&, ::cuda::std::iter_reference_t<_Iter>>,
"cuda::transform_input_output_iterator requires that _InputFn is invocable on the result of "
"dereferencing _Iter");
//! @brief Default constructs a @c transform_input_output_iterator with a value initialized iterator and functors
_CCCL_EXEC_CHECK_DISABLE
_CCCL_TEMPLATE(class _Iter2 = _Iter, class _InputFn2 = _InputFn, class _OutputFn2 = _OutputFn)
_CCCL_REQUIRES(::cuda::std::default_initializable<_Iter2> _CCCL_AND ::cuda::std::default_initializable<_InputFn2>
_CCCL_AND ::cuda::std::default_initializable<_OutputFn2>)
_CCCL_API constexpr transform_input_output_iterator() noexcept(
::cuda::std::is_nothrow_default_constructible_v<_Iter2>
&& ::cuda::std::is_nothrow_default_constructible_v<_InputFn2>
&& ::cuda::std::is_nothrow_default_constructible_v<_OutputFn2>)
: __store_()
{}
//! @brief Constructs a @c transform_input_output_iterator with base iterator, input functor and output functor
//! @param __iter The iterator to transform
//! @param __input_func The input functor to apply to the iterator when reading
//! @param __output_func The output functor to apply to the iterator when writing
_CCCL_EXEC_CHECK_DISABLE
_CCCL_API constexpr transform_input_output_iterator(_Iter __iter, _InputFn __input_func, _OutputFn __output_func) //
noexcept(::cuda::std::is_nothrow_move_constructible_v<_Iter>
&& ::cuda::std::is_nothrow_move_constructible_v<_InputFn>
&& ::cuda::std::is_nothrow_move_constructible_v<_OutputFn>)
: __store_(::cuda::std::move(__iter), ::cuda::std::move(__input_func), ::cuda::std::move(__output_func))
{}
//! @brief Returns a const reference to the base iterator stored
[[nodiscard]] _CCCL_API constexpr const _Iter& base() const& noexcept
{
return __iter();
}
//! @brief Extracts the stored base iterator
_CCCL_EXEC_CHECK_DISABLE
[[nodiscard]] _CCCL_API constexpr _Iter base() && noexcept(::cuda::std::is_nothrow_move_constructible_v<_Iter>)
{
return ::cuda::std::move(__iter());
}
//! @brief Dereferences the @c transform_input_output_iterator. Returns a proxy that transforms values read from the
//! stored iterator via the stored input functor and transforms assigned values via the output functor
_CCCL_EXEC_CHECK_DISABLE
[[nodiscard]] _CCCL_API constexpr reference operator*() const
noexcept(::cuda::std::is_nothrow_copy_constructible_v<_Iter>)
{
return __transform_input_output_proxy{
__iter(), const_cast<_InputFn&>(__input_func()), const_cast<_OutputFn&>(__output_func())};
}
//! @brief Dereferences the @c transform_input_output_iterator. Returns a proxy that transforms values read from the
//! stored iterator via the stored input functor and transforms assigned values via the output functor
_CCCL_EXEC_CHECK_DISABLE
[[nodiscard]] _CCCL_API constexpr reference operator*() noexcept(::cuda::std::is_nothrow_copy_constructible_v<_Iter>)
{
return __transform_input_output_proxy{__iter(), __input_func(), __output_func()};
}
//! @brief Subscripts the @c transform_input_output_iterator. Returns a proxy that transforms values read from the
//! stored iterator adbanvd by a given number of elements via the stored input functor and transforms assigned values
//! via the output functor
//! @param __n The number of elements to advance
_CCCL_EXEC_CHECK_DISABLE
_CCCL_TEMPLATE(class _Iter2 = _Iter)
_CCCL_REQUIRES(::cuda::std::__has_random_access_traversal<_Iter2>)
[[nodiscard]] _CCCL_API constexpr reference operator[](difference_type __n) const
noexcept(::cuda::std::is_nothrow_copy_constructible_v<_Iter2>
&& noexcept(::cuda::std::declval<const _Iter2&>() + __n))
{
return __transform_input_output_proxy{
__iter() + __n, const_cast<_InputFn&>(__input_func()), const_cast<_OutputFn&>(__output_func())};
}
//! @brief Subscripts the @c transform_input_output_iterator. Returns a proxy that transforms values read from the
//! stored iterator adbanvd by a given number of elements via the stored input functor and transforms assigned values
//! via the output functor
//! @param __n The number of elements to advance
_CCCL_EXEC_CHECK_DISABLE
_CCCL_TEMPLATE(class _Iter2 = _Iter)
_CCCL_REQUIRES(::cuda::std::__has_random_access_traversal<_Iter2>)
[[nodiscard]] _CCCL_API constexpr reference operator[](difference_type __n) noexcept(
::cuda::std::is_nothrow_copy_constructible_v<_Iter2> && noexcept(::cuda::std::declval<const _Iter2&>() + __n))
{
return __transform_input_output_proxy{__iter() + __n, __input_func(), __output_func()};
}
//! @brief Increments the stored iterator
_CCCL_EXEC_CHECK_DISABLE
_CCCL_API constexpr transform_input_output_iterator& operator++() noexcept(noexcept(++::cuda::std::declval<_Iter&>()))
{
++__iter();
return *this;
}
//! @brief Increments the stored iterator
_CCCL_EXEC_CHECK_DISABLE
_CCCL_API constexpr transform_input_output_iterator operator++(int) noexcept(
noexcept(++::cuda::std::declval<_Iter&>())
&& ::cuda::std::is_nothrow_copy_constructible_v<_Iter> && ::cuda::std::is_nothrow_copy_constructible_v<_InputFn>
&& ::cuda::std::is_nothrow_copy_constructible_v<_OutputFn>)
{
auto __tmp = *this;
++*this;
return __tmp;
}
//! @brief Decrements the stored iterator
_CCCL_EXEC_CHECK_DISABLE
_CCCL_TEMPLATE(class _Iter2 = _Iter)
_CCCL_REQUIRES(::cuda::std::__has_bidirectional_traversal<_Iter2>)
_CCCL_API constexpr transform_input_output_iterator& operator--() noexcept(noexcept(--::cuda::std::declval<_Iter2&>()))
{
--__iter();
return *this;
}
//! @brief Decrements the stored iterator
_CCCL_EXEC_CHECK_DISABLE
_CCCL_TEMPLATE(class _Iter2 = _Iter)
_CCCL_REQUIRES(::cuda::std::__has_bidirectional_traversal<_Iter2>)
_CCCL_API constexpr transform_input_output_iterator operator--(int) noexcept(
::cuda::std::is_nothrow_copy_constructible_v<_Iter> && noexcept(--::cuda::std::declval<_Iter2&>()))
{
auto __tmp = *this;
--*this;
return __tmp;
}
//! @brief Advances the @c transform_input_output_iterator by a given number of elements
//! @param __n The number of elements to advance
_CCCL_EXEC_CHECK_DISABLE
_CCCL_TEMPLATE(class _Iter2 = _Iter)
_CCCL_REQUIRES(::cuda::std::__has_random_access_traversal<_Iter2>)
_CCCL_API constexpr transform_input_output_iterator&
operator+=(difference_type __n) noexcept(noexcept(::cuda::std::declval<_Iter2&>() += __n))
{
__iter() += __n;
return *this;
}
//! @brief Returns a copy of a @c transform_input_output_iterator advanced by a given number of elements
//! @param __iter The @c transform_input_output_iterator to advance
//! @param __n The number of elements to advance
_CCCL_EXEC_CHECK_DISABLE
template <class _Iter2 = _Iter>
[[nodiscard]] _CCCL_API friend constexpr auto
operator+(const transform_input_output_iterator& __iter, difference_type __n) //
noexcept(::cuda::std::is_nothrow_copy_constructible_v<_Iter>
&& noexcept(::cuda::std::declval<const _Iter2&>() + difference_type{}))
_CCCL_TRAILING_REQUIRES(transform_input_output_iterator)(::cuda::std::__has_random_access_traversal<_Iter2>)
{
return transform_input_output_iterator{__iter.__iter() + __n, __iter.__input_func(), __iter.__output_func()};
}
//! @brief Returns a copy of a @c transform_input_output_iterator advanced by a given number of elements
//! @param __n The number of elements to advance
//! @param __iter The @c transform_input_output_iterator to advance
_CCCL_EXEC_CHECK_DISABLE
template <class _Iter2 = _Iter>
[[nodiscard]] _CCCL_API friend constexpr auto
operator+(difference_type __n, const transform_input_output_iterator& __iter) noexcept(
::cuda::std::is_nothrow_copy_constructible_v<_Iter>
&& noexcept(::cuda::std::declval<const _Iter2&>() + difference_type{}))
_CCCL_TRAILING_REQUIRES(transform_input_output_iterator)(::cuda::std::__has_random_access_traversal<_Iter2>)
{
return transform_input_output_iterator{__iter.__iter() + __n, __iter.__input_func(), __iter.__output_func()};
}
//! @brief Decrements the @c transform_input_output_iterator by a given number of elements
//! @param __n The number of elements to decrement
_CCCL_EXEC_CHECK_DISABLE
_CCCL_TEMPLATE(class _Iter2 = _Iter)
_CCCL_REQUIRES(::cuda::std::__has_random_access_traversal<_Iter2>)
_CCCL_API constexpr transform_input_output_iterator&
operator-=(difference_type __n) noexcept(noexcept(::cuda::std::declval<_Iter2&>() -= __n))
{
__iter() -= __n;
return *this;
}
//! @brief Returns a copy of a @c transform_input_output_iterator decremented by a given number of elements
//! @param __iter The @c transform_input_output_iterator to decrement
//! @param __n The number of elements to decrement
_CCCL_EXEC_CHECK_DISABLE
template <class _Iter2 = _Iter>
[[nodiscard]] _CCCL_API friend constexpr auto
operator-(const transform_input_output_iterator& __iter, difference_type __n) //
noexcept(::cuda::std::is_nothrow_copy_constructible_v<_Iter>
&& noexcept(::cuda::std::declval<const _Iter2&>() - difference_type{}))
_CCCL_TRAILING_REQUIRES(transform_input_output_iterator)(::cuda::std::__has_random_access_traversal<_Iter2>)
{
return transform_input_output_iterator{__iter.__iter() - __n, __iter.__input_func(), __iter.__output_func()};
}
template <class _Iter2>
static constexpr bool __can_difference =
(::cuda::std::__has_random_access_traversal<_Iter2> || ::cuda::std::sized_sentinel_for<_Iter2, _Iter2>);
template <class _Iter2>
static constexpr bool __noexcept_difference =
noexcept(::cuda::std::declval<const _Iter2&>() - ::cuda::std::declval<const _Iter2&>());
//! @brief Returns the distance between two @c transform_input_output_iterator
_CCCL_EXEC_CHECK_DISABLE
template <class _Iter2 = _Iter>
[[nodiscard]] _CCCL_API friend constexpr auto operator-(const transform_input_output_iterator& __lhs,
const transform_input_output_iterator& __rhs) //
noexcept(__noexcept_difference<_Iter2>) _CCCL_TRAILING_REQUIRES(difference_type)(__can_difference<_Iter2>)
{
return __lhs.__iter() - __rhs.__iter();
}
//! @brief Compares two @c transform_input_output_iterator for equality by comparing the stored iterators
_CCCL_EXEC_CHECK_DISABLE
template <class _Iter2 = _Iter>
[[nodiscard]] _CCCL_API friend constexpr auto
operator==(const transform_input_output_iterator& __lhs, const transform_input_output_iterator& __rhs) noexcept(
noexcept(::cuda::std::declval<const _Iter2&>() == ::cuda::std::declval<const _Iter2&>()))
_CCCL_TRAILING_REQUIRES(bool)(::cuda::std::equality_comparable<_Iter2>)
{
return __lhs.__iter() == __rhs.__iter();
}
#if _CCCL_STD_VER <= 2017
//! @brief Compares two @c transform_input_output_iterator for inequality by comparing the stored iterators
_CCCL_EXEC_CHECK_DISABLE
template <class _Iter2 = _Iter>
[[nodiscard]] _CCCL_API friend constexpr auto
operator!=(const transform_input_output_iterator& __lhs, const transform_input_output_iterator& __rhs) noexcept(
noexcept(::cuda::std::declval<const _Iter2&>() != ::cuda::std::declval<const _Iter2&>()))
_CCCL_TRAILING_REQUIRES(bool)(::cuda::std::equality_comparable<_Iter2>)
{
return __lhs.__iter() != __rhs.__iter();
}
#endif // _CCCL_STD_VER <= 2017
//! @brief Compares two @c transform_input_output_iterator for less than by comparing the stored iterators
_CCCL_EXEC_CHECK_DISABLE
template <class _Iter2 = _Iter>
[[nodiscard]] _CCCL_API friend constexpr auto
operator<(const transform_input_output_iterator& __lhs, const transform_input_output_iterator& __rhs) noexcept(
noexcept(::cuda::std::declval<const _Iter2&>() < ::cuda::std::declval<const _Iter2&>()))
_CCCL_TRAILING_REQUIRES(bool)(::cuda::std::__has_random_access_traversal<_Iter2>)
{
return __lhs.__iter() < __rhs.__iter();
}
//! @brief Compares two @c transform_input_output_iterator for greater than by comparing the stored iterators
_CCCL_EXEC_CHECK_DISABLE
template <class _Iter2 = _Iter>
[[nodiscard]] _CCCL_API friend constexpr auto
operator>(const transform_input_output_iterator& __lhs, const transform_input_output_iterator& __rhs) noexcept(
noexcept(::cuda::std::declval<const _Iter2&>() < ::cuda::std::declval<const _Iter2&>()))
_CCCL_TRAILING_REQUIRES(bool)(::cuda::std::__has_random_access_traversal<_Iter2>)
{
return __lhs.__iter() > __rhs.__iter();
}
//! @brief Compares two @c transform_input_output_iterator for less equal by comparing the stored iterators
_CCCL_EXEC_CHECK_DISABLE
template <class _Iter2 = _Iter>
[[nodiscard]] _CCCL_API friend constexpr auto
operator<=(const transform_input_output_iterator& __lhs, const transform_input_output_iterator& __rhs) noexcept(
noexcept(::cuda::std::declval<const _Iter2&>() < ::cuda::std::declval<const _Iter2&>()))
_CCCL_TRAILING_REQUIRES(bool)(::cuda::std::__has_random_access_traversal<_Iter2>)
{
return __lhs.__iter() <= __rhs.__iter();
}
//! @brief Compares two @c transform_input_output_iterator for greater equal by comparing the stored iterators
_CCCL_EXEC_CHECK_DISABLE
template <class _Iter2 = _Iter>
[[nodiscard]] _CCCL_API friend constexpr auto
operator>=(const transform_input_output_iterator& __lhs, const transform_input_output_iterator& __rhs) noexcept(
noexcept(::cuda::std::declval<const _Iter2&>() < ::cuda::std::declval<const _Iter2&>()))
_CCCL_TRAILING_REQUIRES(bool)(::cuda::std::__has_random_access_traversal<_Iter2>)
{
return __lhs.__iter() >= __rhs.__iter();
}
#if _LIBCUDACXX_HAS_SPACESHIP_OPERATOR()
//! @brief Three-way-compares two @c transform_input_output_iterator, directly three-way-comparing the stored
//! iterators
_CCCL_EXEC_CHECK_DISABLE
template <class _Iter2 = _Iter>
[[nodiscard]] _CCCL_API friend constexpr auto
operator<=>(const transform_input_output_iterator& __lhs, const transform_input_output_iterator& __rhs) noexcept(
noexcept(::cuda::std::declval<const _Iter2&>() <=> ::cuda::std::declval<const _Iter2&>()))
_CCCL_TRAILING_REQUIRES(bool)(
::cuda::std::__has_random_access_traversal<_Iter2>&& ::cuda::std::three_way_comparable<_Iter2>)
{
return __lhs.__iter() <=> __rhs.__iter();
}
#endif // !_LIBCUDACXX_HAS_NO_SPACESHIP_OPERATOR
};
//! @brief make_transform_output_iterator creates a @c transform_input_output_iterator from an iterator, an input
//! functor and an output functor
//! @param __iter The iterator pointing to the input range of the newly created @c transform_input_output_iterator.
//! @param __input_fun The input functor used to transform the range when read
//! @param __output_fun The output functor used to transform the range when written
//! @relates transform_input_output_iterator
template <class _InputFn, class _OutputFn, class _Iter>
[[nodiscard]] _CCCL_API constexpr auto
make_transform_input_output_iterator(_Iter __iter, _InputFn __input_fun, _OutputFn __output_fun)
{
return transform_input_output_iterator<_InputFn, _OutputFn, _Iter>{__iter, __input_fun, __output_fun};
}
//! @}
_CCCL_END_NAMESPACE_CUDA
#ifndef _CCCL_DOXYGEN_INVOKED
# if _CCCL_HAS_HOST_STD_LIB()
_CCCL_BEGIN_NAMESPACE_STD
//! transform_input_output_iterator is a C++20 iterator, so it does not play well with legacy STL features like
//! std::distance. To work around that specialize those functions for transform_input_output_iterator
template <class _Diff, class _InputFn, class _OutputFn, class _Iter>
_CCCL_HOST_API constexpr void
advance(::cuda::transform_input_output_iterator<_InputFn, _OutputFn, _Iter>& __iter, _Diff __diff)
{
::cuda::std::advance(__iter, ::cuda::std::move(__diff));
}
template <class _InputFn, class _OutputFn, class _Iter>
[[nodiscard]] _CCCL_HOST_API constexpr ::cuda::std::iter_difference_t<_Iter>
distance(::cuda::transform_input_output_iterator<_InputFn, _OutputFn, _Iter> __first,
::cuda::transform_input_output_iterator<_InputFn, _OutputFn, _Iter> __last)
{
return ::cuda::std::distance(::cuda::std::move(__first), ::cuda::std::move(__last));
}
template <class _InputFn, class _OutputFn, class _Iter>
[[nodiscard]] _CCCL_HOST_API constexpr ::cuda::transform_input_output_iterator<_InputFn, _OutputFn, _Iter>
next(::cuda::transform_input_output_iterator<_InputFn, _OutputFn, _Iter> __iter,
::cuda::std::iter_difference_t<_Iter> __n = 1)
{
_CCCL_ASSERT(__n >= 0 || ::cuda::std::__has_bidirectional_traversal<_Iter>,
"Attempt to std::next(it, n) with negative n on a non-bidirectional iterator");
::cuda::std::advance(__iter, __n);
return __iter;
}
template <class _InputFn, class _OutputFn, class _Iter>
[[nodiscard]] _CCCL_HOST_API constexpr ::cuda::transform_input_output_iterator<_InputFn, _OutputFn, _Iter>
prev(::cuda::transform_input_output_iterator<_InputFn, _OutputFn, _Iter> __iter,
::cuda::std::iter_difference_t<_Iter> __n = 1)
{
_CCCL_ASSERT(__n <= 0 || ::cuda::std::__has_bidirectional_traversal<_Iter>,
"Attempt to std::prev(it, +n) on a non-bidi iterator");
::cuda::std::advance(__iter, -__n);
return __iter;
}
_CCCL_END_NAMESPACE_STD
# endif // _CCCL_HAS_HOST_STD_LIB()
#endif // _CCCL_DOXYGEN_INVOKED
#include <cuda/std/__cccl/epilogue.h>
#endif // _CUDA___ITERATOR_TRANSFORM_INPUT_OUTPUT_ITERATOR_H

View File

@@ -0,0 +1,582 @@
//===----------------------------------------------------------------------===//
//
// 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___ITERATOR_TRANSFORM_ITERATOR_H
#define _CUDA___ITERATOR_TRANSFORM_ITERATOR_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/__fwd/iterator.h>
#if _LIBCUDACXX_HAS_SPACESHIP_OPERATOR()
# include <cuda/std/__compare/three_way_comparable.h>
#endif // _LIBCUDACXX_HAS_SPACESHIP_OPERATOR()
#include <cuda/std/__concepts/constructible.h>
#include <cuda/std/__concepts/derived_from.h>
#include <cuda/std/__concepts/equality_comparable.h>
#include <cuda/std/__concepts/invocable.h>
#include <cuda/std/__functional/invoke.h>
#include <cuda/std/__iterator/advance.h>
#include <cuda/std/__iterator/concepts.h>
#include <cuda/std/__iterator/distance.h>
#include <cuda/std/__iterator/iterator_traits.h>
#include <cuda/std/__ranges/compressed_movable_box.h>
#include <cuda/std/__ranges/concepts.h>
#include <cuda/std/__ranges/movable_box.h>
#include <cuda/std/__type_traits/conditional.h>
#include <cuda/std/__type_traits/enable_if.h>
#include <cuda/std/__type_traits/is_nothrow_default_constructible.h>
#include <cuda/std/__type_traits/is_nothrow_move_constructible.h>
#include <cuda/std/__type_traits/is_object.h>
#include <cuda/std/__type_traits/is_reference.h>
#include <cuda/std/__type_traits/remove_cvref.h>
#include <cuda/std/__utility/declval.h>
#include <cuda/std/__utility/forward.h>
#include <cuda/std/__utility/move.h>
#include <cuda/std/__cccl/prologue.h>
_CCCL_BEGIN_NAMESPACE_CUDA
//! @addtogroup iterators
//! @{
template <class, class, class = void>
struct __transform_iterator_category_base
{};
template <class _Fn, class _Iter>
struct __transform_iterator_category_base<_Fn,
_Iter,
::cuda::std::enable_if_t<::cuda::std::__has_forward_traversal<_Iter>>>
{
using _Cat = typename ::cuda::std::iterator_traits<_Iter>::iterator_category;
using iterator_category = ::cuda::std::conditional_t<
::cuda::std::is_reference_v<::cuda::std::invoke_result_t<_Fn&, ::cuda::std::iter_reference_t<_Iter>>>,
::cuda::std::conditional_t<::cuda::std::derived_from<_Cat, ::cuda::std::contiguous_iterator_tag>,
::cuda::std::random_access_iterator_tag,
_Cat>,
::cuda::std::input_iterator_tag>;
};
template <class _Fn, class _Iter, bool = (::cuda::std::__has_random_access_traversal<_Iter>)>
inline constexpr bool __transform_iterator_nothrow_subscript = false;
template <class _Fn, class _Iter>
inline constexpr bool __transform_iterator_nothrow_subscript<_Fn, _Iter, true> =
noexcept(::cuda::std::invoke(::cuda::std::declval<_Fn&>(), ::cuda::std::declval<_Iter&>()[0]));
//! @brief @c transform_iterator is an iterator which represents a pointer into a range of values after transformation
//! by a functor. This iterator is useful for creating a range filled with the result of applying an operation to
//! another range without either explicitly storing it in memory, or explicitly executing the transformation. Using
//! @c transform_iterator facilitates kernel fusion by deferring the execution of a transformation until the value is
//! needed while saving both memory capacity and bandwidth.
//!
//! The following code snippet demonstrates how to create a @c transform_iterator which represents the result of
//! @c sqrtf applied to the contents of a @c thrust::device_vector.
//!
//! @code
//! #include <cuda/iterator>
//! #include <thrust/device_vector.h>
//!
//! struct square_root
//! {
//! __host__ __device__
//! float operator()(float x) const
//! {
//! return sqrtf(x);
//! }
//! };
//!
//! int main()
//! {
//! thrust::device_vector<float> v{1.0f, 4.0f, 9.0f, 16.0f};
//!
//! using FloatIterator = thrust::device_vector<float>::iterator;
//!
//! cuda::transform_iterator iter(v.begin(), square_root{});
//!
//! *iter; // returns 1.0f
//! iter[0]; // returns 1.0f;
//! iter[1]; // returns 2.0f;
//! iter[2]; // returns 3.0f;
//! iter[3]; // returns 4.0f;
//!
//! // iter[4] is an out-of-bounds error
//! }
//! @endcode
//!
//! This next example demonstrates how to use a @c transform_iterator with the @c thrust::reduce functor to compute the
//! sum of squares of a sequence. We will create temporary @c transform_iterators utilising class template argument
//! deduction avoid explicitly specifying their type:
//!
//! @code
//! #include <cuda/iterator>
//! #include <thrust/device_vector.h>
//! #include <thrust/reduce.h>
//! #include <iostream>
//!
//! struct square
//! {
//! __host__ __device__
//! float operator()(float x) const
//! {
//! return x * x;
//! }
//! };
//!
//! int main()
//! {
//! // initialize a device array
//! thrust::device_vector<float> v(4);
//! v[0] = 1.0f;
//! v[1] = 2.0f;
//! v[2] = 3.0f;
//! thrust::device_vector<float> v{1.0f, 2.0f, 3.0f, 4.0f};
//! thrust::reduce(cuda::transform_iterator{v.begin(), square{}},
//! cuda::transform_iterator{v.end(), square{}});
//!
//! std::cout << "sum of squares: " << sum_of_squares << '\n';
//! return 0;
//! }
//! @endcode
template <class _Fn, class _Iter>
class transform_iterator : public __transform_iterator_category_base<_Fn, _Iter>
{
static_assert(::cuda::std::is_object_v<_Fn>, "cuda::transform_iterator requires that _Fn is a functor object");
static_assert(::cuda::std::regular_invocable<_Fn&, ::cuda::std::iter_reference_t<_Iter>>,
"cuda::transform_iterator requires that _Fn is invocable with iter_reference_t<_Iter>");
static_assert(::cuda::std::__can_reference<::cuda::std::invoke_result_t<_Fn&, ::cuda::std::iter_reference_t<_Iter>>>,
"cuda::transform_iterator requires that the return type of _Fn is referenceable");
// Not a base because then the friend operators would be ambiguous
::cuda::std::__compressed_movable_box<_Iter, _Fn> __store_;
[[nodiscard]] _CCCL_API constexpr _Iter& __iter() noexcept
{
return __store_.template __get<0>();
}
[[nodiscard]] _CCCL_API constexpr const _Iter& __iter() const noexcept
{
return __store_.template __get<0>();
}
[[nodiscard]] _CCCL_API constexpr _Fn& __func() noexcept
{
return __store_.template __get<1>();
}
[[nodiscard]] _CCCL_API constexpr const _Fn& __func() const noexcept
{
return __store_.template __get<1>();
}
public:
using iterator_concept = ::cuda::std::conditional_t<
::cuda::std::__has_random_access_traversal<_Iter>,
::cuda::std::random_access_iterator_tag,
::cuda::std::conditional_t<::cuda::std::__has_bidirectional_traversal<_Iter>,
::cuda::std::bidirectional_iterator_tag,
::cuda::std::conditional_t<::cuda::std::__has_forward_traversal<_Iter>,
::cuda::std::forward_iterator_tag,
::cuda::std::input_iterator_tag>>>;
using value_type =
::cuda::std::remove_cvref_t<::cuda::std::invoke_result_t<_Fn&, ::cuda::std::iter_reference_t<_Iter>>>;
using difference_type = ::cuda::std::iter_difference_t<_Iter>;
// Those are technically not to spec, but pre-ranges iterator_traits do not work properly with iterators that do not
// define all 5 aliases, see https://en.cppreference.com/w/cpp/iterator/iterator_traits.html
using reference = ::cuda::std::invoke_result_t<_Fn&, ::cuda::std::iter_reference_t<_Iter>>;
using pointer = void;
//! @brief Default constructs a @c transform_iterator with a value initialized iterator and functor
_CCCL_EXEC_CHECK_DISABLE
_CCCL_TEMPLATE(class _Iter2 = _Iter, class _Fn2 = _Fn)
_CCCL_REQUIRES(::cuda::std::default_initializable<_Iter2> _CCCL_AND ::cuda::std::default_initializable<_Fn2>)
_CCCL_API constexpr transform_iterator() noexcept(
::cuda::std::is_nothrow_default_constructible_v<_Iter2> && ::cuda::std::is_nothrow_default_constructible_v<_Fn2>)
: __store_()
{}
//! @brief Constructs a @c transform_iterator with a given iterator and functor
//! @param __iter The iterator to transform
//! @param __func The functor to apply to the iterator
_CCCL_EXEC_CHECK_DISABLE
_CCCL_API constexpr transform_iterator(_Iter __iter, _Fn __func) noexcept(
::cuda::std::is_nothrow_move_constructible_v<_Iter> && ::cuda::std::is_nothrow_move_constructible_v<_Fn>)
: __store_(::cuda::std::move(__iter), ::cuda::std::move(__func))
{}
//! @brief Returns a const reference to the stored iterator
[[nodiscard]] _CCCL_API constexpr const _Iter& base() const& noexcept
{
return __iter();
}
//! @brief Extracts the stored iterator
_CCCL_EXEC_CHECK_DISABLE
[[nodiscard]] _CCCL_API constexpr _Iter base() && noexcept(::cuda::std::is_nothrow_move_constructible_v<_Iter>)
{
return ::cuda::std::move(__iter());
}
//! @brief Dereferences the stored iterator and applies the stored functor to the result
_CCCL_EXEC_CHECK_DISABLE
#ifndef _CCCL_DOXYGEN_INVOKED // Doxygen has issues with the constraint
_CCCL_TEMPLATE(class _Iter2 = _Iter)
_CCCL_REQUIRES(::cuda::std::regular_invocable<const _Fn&, ::cuda::std::iter_reference_t<const _Iter2>>)
#endif // !_CCCL_DOXYGEN_INVOKED
[[nodiscard]] _CCCL_API constexpr reference operator*() const
noexcept(noexcept(::cuda::std::invoke(::cuda::std::declval<const _Fn&>(), *::cuda::std::declval<const _Iter2&>())))
{
return ::cuda::std::invoke(__func(), *__iter());
}
//! @cond
//! @brief Dereferences the stored iterator and applies the stored functor to the result
//! @note This is a cludge against the fact that the iterator concepts requires `const Iter` but a user might have
//! forgotten to const qualify the call operator
_CCCL_EXEC_CHECK_DISABLE
#ifndef _CCCL_DOXYGEN_INVOKED // Doxygen has issues with the constraint
_CCCL_TEMPLATE(class _Iter2 = _Iter)
_CCCL_REQUIRES((!::cuda::std::regular_invocable<const _Fn&, ::cuda::std::iter_reference_t<const _Iter2>>) )
#endif // !_CCCL_DOXYGEN_INVOKED
[[nodiscard]] _CCCL_API constexpr reference operator*() const
noexcept(noexcept(::cuda::std::invoke(::cuda::std::declval<_Fn&>(), *::cuda::std::declval<const _Iter2&>())))
{
return ::cuda::std::invoke(const_cast<_Fn&>(__func()), *__iter());
}
//! @endcond
//! @brief Dereferences the stored iterator and applies the stored functor to the result
_CCCL_EXEC_CHECK_DISABLE
[[nodiscard]] _CCCL_API constexpr reference
operator*() noexcept(noexcept(::cuda::std::invoke(::cuda::std::declval<_Fn&>(), *::cuda::std::declval<_Iter&>())))
{
return ::cuda::std::invoke(__func(), *__iter());
}
//! @brief Subscripts the stored iterator by a number of elements and applies the stored functor to the result
//! @param __n The number of elements to advance by
_CCCL_EXEC_CHECK_DISABLE
#ifndef _CCCL_DOXYGEN_INVOKED // Doxygen has issues with the constraint
_CCCL_TEMPLATE(class _Iter2 = _Iter)
_CCCL_REQUIRES(::cuda::std::__has_random_access_traversal<_Iter2>
_CCCL_AND ::cuda::std::regular_invocable<const _Fn&, ::cuda::std::iter_reference_t<const _Iter2>>)
#endif // !_CCCL_DOXYGEN_INVOKED
[[nodiscard]] _CCCL_API constexpr reference operator[](difference_type __n) const
noexcept(__transform_iterator_nothrow_subscript<const _Fn, _Iter2>)
{
return ::cuda::std::invoke(__func(), __iter()[__n]);
}
//! @cond
//! @brief Subscripts the stored iterator by a number of elements and applies the stored functor to the result
//! @param __n The number of elements to advance by
//! @note This is a cludge against the fact that the iterator concepts requires `const Iter` but a user might have
//! forgotten to const qualify the call operator
_CCCL_EXEC_CHECK_DISABLE
#ifndef _CCCL_DOXYGEN_INVOKED // Doxygen has issues with the constraint
_CCCL_TEMPLATE(class _Iter2 = _Iter)
_CCCL_REQUIRES(::cuda::std::__has_random_access_traversal<_Iter2> _CCCL_AND(
!::cuda::std::regular_invocable<const _Fn&, ::cuda::std::iter_reference_t<const _Iter2>>))
#endif // !_CCCL_DOXYGEN_INVOKED
[[nodiscard]] _CCCL_API constexpr reference operator[](difference_type __n) const
noexcept(__transform_iterator_nothrow_subscript<_Fn, _Iter2>)
{
return ::cuda::std::invoke(const_cast<_Fn&>(__func()), __iter()[__n]);
}
//! @endcond
//! @brief Subscripts the stored iterator by a number of elements and applies the stored functor to the result
//! @param __n The number of elements to advance by
_CCCL_EXEC_CHECK_DISABLE
#ifndef _CCCL_DOXYGEN_INVOKED // Doxygen has issues with the constraint
_CCCL_TEMPLATE(class _Iter2 = _Iter)
_CCCL_REQUIRES(::cuda::std::__has_random_access_traversal<_Iter2>)
#endif // !_CCCL_DOXYGEN_INVOKED
[[nodiscard]] _CCCL_API constexpr reference
operator[](difference_type __n) noexcept(__transform_iterator_nothrow_subscript<_Fn, _Iter2>)
{
return ::cuda::std::invoke(__func(), __iter()[__n]);
}
//! @brief Increments the stored iterator
_CCCL_EXEC_CHECK_DISABLE
_CCCL_API constexpr transform_iterator& operator++() noexcept(noexcept(++::cuda::std::declval<_Iter&>()))
{
++__iter();
return *this;
}
//! @brief Increments the stored iterator
_CCCL_EXEC_CHECK_DISABLE
_CCCL_API constexpr auto operator++(int) noexcept(noexcept(++::cuda::std::declval<_Iter&>()))
{
if constexpr (::cuda::std::__has_forward_traversal<_Iter>)
{
auto __tmp = *this;
++*this;
return __tmp;
}
else
{
++__iter();
}
}
//! @brief Decrements the stored iterator
_CCCL_EXEC_CHECK_DISABLE
_CCCL_TEMPLATE(class _Iter2 = _Iter)
_CCCL_REQUIRES(::cuda::std::__has_bidirectional_traversal<_Iter2>)
_CCCL_API constexpr transform_iterator& operator--() noexcept(noexcept(--::cuda::std::declval<_Iter2&>()))
{
--__iter();
return *this;
}
//! @brief Decrements the stored iterator
_CCCL_EXEC_CHECK_DISABLE
_CCCL_TEMPLATE(class _Iter2 = _Iter)
_CCCL_REQUIRES(::cuda::std::__has_bidirectional_traversal<_Iter2>)
_CCCL_API constexpr transform_iterator operator--(int) noexcept(
::cuda::std::is_nothrow_copy_constructible_v<_Iter> && noexcept(--::cuda::std::declval<_Iter2&>()))
{
auto __tmp = *this;
--*this;
return __tmp;
}
//! @brief Increments the @c transform_iterator by a given number of elements
//! @param __n The number of elements to increment
_CCCL_EXEC_CHECK_DISABLE
_CCCL_TEMPLATE(class _Iter2 = _Iter)
_CCCL_REQUIRES(::cuda::std::__has_random_access_traversal<_Iter2>)
_CCCL_API constexpr transform_iterator&
operator+=(difference_type __n) noexcept(noexcept(::cuda::std::declval<_Iter2&>() += __n))
{
__iter() += __n;
return *this;
}
//! @brief Returns a copy of a @c transform_iterator advanced by a given number of elements
//! @param __iter The @c transform_iterator to advance
//! @param __n The amount of elements to increment
_CCCL_EXEC_CHECK_DISABLE
template <class _Iter2 = _Iter>
[[nodiscard]] _CCCL_API friend constexpr auto operator+(const transform_iterator& __iter, difference_type __n)
_CCCL_TRAILING_REQUIRES(transform_iterator)(::cuda::std::__has_random_access_traversal<_Iter2>)
{
return transform_iterator{__iter.__iter() + __n, __iter.__func()};
}
//! @brief Returns a copy of a @c transform_iterator advanced by a given number of elements
//! @param __n The amount of elements to increment
//! @param __iter The @c transform_iterator to advance
_CCCL_EXEC_CHECK_DISABLE
template <class _Iter2 = _Iter>
[[nodiscard]] _CCCL_API friend constexpr auto operator+(difference_type __n, const transform_iterator& __iter)
_CCCL_TRAILING_REQUIRES(transform_iterator)(::cuda::std::__has_random_access_traversal<_Iter2>)
{
return transform_iterator{__iter.__iter() + __n, __iter.__func()};
}
//! @brief Decrements the @c transform_iterator by a given number of elements
//! @param __n The number of elements to decrement
_CCCL_EXEC_CHECK_DISABLE
_CCCL_TEMPLATE(class _Iter2 = _Iter)
_CCCL_REQUIRES(::cuda::std::__has_random_access_traversal<_Iter2>)
_CCCL_API constexpr transform_iterator&
operator-=(difference_type __n) noexcept(noexcept(::cuda::std::declval<_Iter2&>() -= __n))
{
__iter() -= __n;
return *this;
}
//! @brief Returns a copy of a @c transform_iterator decremented by a given number of elements
//! @param __iter The @c transform_iterator to decrement
//! @param __n The amount of elements to decrement
_CCCL_EXEC_CHECK_DISABLE
template <class _Iter2 = _Iter>
[[nodiscard]] _CCCL_API friend constexpr auto operator-(const transform_iterator& __iter, difference_type __n)
_CCCL_TRAILING_REQUIRES(transform_iterator)(::cuda::std::__has_random_access_traversal<_Iter2>)
{
return transform_iterator{__iter.__iter() - __n, __iter.__func()};
}
template <class _Iter2>
static constexpr bool __can_difference =
(::cuda::std::__has_random_access_traversal<_Iter2> || ::cuda::std::sized_sentinel_for<_Iter2, _Iter2>);
template <class _Iter2>
static constexpr bool __noexcept_difference =
noexcept(::cuda::std::declval<const _Iter2&>() - ::cuda::std::declval<const _Iter2&>());
//! @brief Returns the distance between two @c transform_iterator
_CCCL_EXEC_CHECK_DISABLE
template <class _Iter2 = _Iter>
[[nodiscard]] _CCCL_API friend constexpr auto
operator-(const transform_iterator& __lhs, const transform_iterator& __rhs) noexcept(__noexcept_difference<_Iter2>)
_CCCL_TRAILING_REQUIRES(difference_type)(__can_difference<_Iter2>)
{
return __lhs.__iter() - __rhs.__iter();
}
//! @brief Compares two @c transform_iterator for equality by comparing the stored iterators
_CCCL_EXEC_CHECK_DISABLE
template <class _Iter2 = _Iter>
[[nodiscard]] _CCCL_API friend constexpr auto
operator==(const transform_iterator& __lhs, const transform_iterator& __rhs) noexcept(
noexcept(::cuda::std::declval<const _Iter2&>() == ::cuda::std::declval<const _Iter2&>()))
_CCCL_TRAILING_REQUIRES(bool)(::cuda::std::equality_comparable<_Iter2>)
{
return __lhs.__iter() == __rhs.__iter();
}
#if _CCCL_STD_VER <= 2017
//! @brief Compares two @c transform_iterator for inequality by comparing the stored iterators
_CCCL_EXEC_CHECK_DISABLE
template <class _Iter2 = _Iter>
[[nodiscard]] _CCCL_API friend constexpr auto
operator!=(const transform_iterator& __lhs, const transform_iterator& __rhs) noexcept(
noexcept(::cuda::std::declval<const _Iter2&>() != ::cuda::std::declval<const _Iter2&>()))
_CCCL_TRAILING_REQUIRES(bool)(::cuda::std::equality_comparable<_Iter2>)
{
return __lhs.__iter() != __rhs.__iter();
}
#endif // _CCCL_STD_VER <= 2017
#if _LIBCUDACXX_HAS_SPACESHIP_OPERATOR()
//! @brief Three-way-compares two @c transform_iterator, directly three-way-comparing the stored iterators
_CCCL_EXEC_CHECK_DISABLE
template <class _Iter2 = _Iter>
[[nodiscard]] _CCCL_API friend constexpr auto
operator<=>(const transform_iterator& __lhs, const transform_iterator& __rhs) noexcept(
noexcept(::cuda::std::declval<const _Iter2&>() <=> ::cuda::std::declval<const _Iter2&>()))
_CCCL_TRAILING_REQUIRES(bool)(
::cuda::std::__has_random_access_traversal<_Iter2>&& ::cuda::std::three_way_comparable<_Iter2>)
{
return __lhs.__iter() <=> __rhs.__iter();
}
#else // ^^^ _LIBCUDACXX_HAS_SPACESHIP_OPERATOR() ^^^ / vvv !_LIBCUDACXX_HAS_SPACESHIP_OPERATOR() vvv
//! @brief Compares two @c transform_iterator for less than by comparing the stored iterators
_CCCL_EXEC_CHECK_DISABLE
template <class _Iter2 = _Iter>
[[nodiscard]] _CCCL_API friend constexpr auto
operator<(const transform_iterator& __lhs, const transform_iterator& __rhs) noexcept(
noexcept(::cuda::std::declval<const _Iter2&>() < ::cuda::std::declval<const _Iter2&>()))
_CCCL_TRAILING_REQUIRES(bool)(::cuda::std::__has_random_access_traversal<_Iter2>)
{
return __lhs.__iter() < __rhs.__iter();
}
//! @brief Compares two @c transform_iterator for greater than by comparing the stored iterators
_CCCL_EXEC_CHECK_DISABLE
template <class _Iter2 = _Iter>
[[nodiscard]] _CCCL_API friend constexpr auto
operator>(const transform_iterator& __lhs, const transform_iterator& __rhs) noexcept(
noexcept(::cuda::std::declval<const _Iter2&>() < ::cuda::std::declval<const _Iter2&>()))
_CCCL_TRAILING_REQUIRES(bool)(::cuda::std::__has_random_access_traversal<_Iter2>)
{
return __lhs.__iter() > __rhs.__iter();
}
//! @brief Compares two @c transform_iterator for less equal by comparing the stored iterators
_CCCL_EXEC_CHECK_DISABLE
template <class _Iter2 = _Iter>
[[nodiscard]] _CCCL_API friend constexpr auto
operator<=(const transform_iterator& __lhs, const transform_iterator& __rhs) noexcept(
noexcept(::cuda::std::declval<const _Iter2&>() < ::cuda::std::declval<const _Iter2&>()))
_CCCL_TRAILING_REQUIRES(bool)(::cuda::std::__has_random_access_traversal<_Iter2>)
{
return __lhs.__iter() <= __rhs.__iter();
}
//! @brief Compares two @c transform_iterator for greater equal by comparing the stored iterators
_CCCL_EXEC_CHECK_DISABLE
template <class _Iter2 = _Iter>
[[nodiscard]] _CCCL_API friend constexpr auto
operator>=(const transform_iterator& __lhs, const transform_iterator& __rhs) noexcept(
noexcept(::cuda::std::declval<const _Iter2&>() < ::cuda::std::declval<const _Iter2&>()))
_CCCL_TRAILING_REQUIRES(bool)(::cuda::std::__has_random_access_traversal<_Iter2>)
{
return __lhs.__iter() >= __rhs.__iter();
}
#endif // !_LIBCUDACXX_HAS_SPACESHIP_OPERATOR()
};
//! @brief Creates a @c transform_iterator from a base iterator and a functor
//! @param __iter The iterator of the input range
//! @param __fun The functor used to transform the input range
//! @relates transform_iterator
template <class _Fn, class _Iter>
[[nodiscard]] _CCCL_API constexpr auto make_transform_iterator(_Iter __iter, _Fn __fun)
{
return transform_iterator<_Fn, _Iter>{__iter, __fun};
}
//! @}
_CCCL_END_NAMESPACE_CUDA
#ifndef _CCCL_DOXYGEN_INVOKED
# if _CCCL_HAS_HOST_STD_LIB()
_CCCL_BEGIN_NAMESPACE_STD
//! transform_iterator is a C++20 iterator, so it does not play well with legacy STL features like std::distance
//! To work around that specialize those functions for transform_iterator
template <class _Diff, class _Fn, class _Iter>
_CCCL_HOST_API constexpr void advance(::cuda::transform_iterator<_Fn, _Iter>& __iter, _Diff __diff)
{
::cuda::std::advance(__iter, ::cuda::std::move(__diff));
}
template <class _Fn, class _Iter>
[[nodiscard]] _CCCL_HOST_API constexpr ::cuda::std::iter_difference_t<_Iter>
distance(::cuda::transform_iterator<_Fn, _Iter> __first, ::cuda::transform_iterator<_Fn, _Iter> __last)
{
return ::cuda::std::distance(::cuda::std::move(__first), ::cuda::std::move(__last));
}
template <class _Fn, class _Iter>
[[nodiscard]] _CCCL_HOST_API constexpr ::cuda::transform_iterator<_Fn, _Iter>
next(::cuda::transform_iterator<_Fn, _Iter> __iter, ::cuda::std::iter_difference_t<_Iter> __n = 1)
{
_CCCL_ASSERT(__n >= 0 || ::cuda::std::__has_bidirectional_traversal<_Iter>,
"Attempt to std::next(it, n) with negative n on a non-bidirectional iterator");
::cuda::std::advance(__iter, __n);
return __iter;
}
template <class _Fn, class _Iter>
[[nodiscard]] _CCCL_HOST_API constexpr ::cuda::transform_iterator<_Fn, _Iter>
prev(::cuda::transform_iterator<_Fn, _Iter> __iter, ::cuda::std::iter_difference_t<_Iter> __n = 1)
{
_CCCL_ASSERT(__n <= 0 || ::cuda::std::__has_bidirectional_traversal<_Iter>,
"Attempt to std::prev(it, +n) on a non-bidi iterator");
::cuda::std::advance(__iter, -__n);
return __iter;
}
_CCCL_END_NAMESPACE_STD
# endif // _CCCL_HAS_HOST_STD_LIB()
#endif // _CCCL_DOXYGEN_INVOKED
#include <cuda/std/__cccl/epilogue.h>
#endif // _CUDA___ITERATOR_TRANSFORM_ITERATOR_H

View File

@@ -0,0 +1,535 @@
//===----------------------------------------------------------------------===//
//
// 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___ITERATOR_TRANSFORM_OUTPUT_ITERATOR_H
#define _CUDA___ITERATOR_TRANSFORM_OUTPUT_ITERATOR_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/__fwd/iterator.h>
#if _LIBCUDACXX_HAS_SPACESHIP_OPERATOR()
# include <cuda/std/__compare/three_way_comparable.h>
#endif // _LIBCUDACXX_HAS_SPACESHIP_OPERATOR()
#include <cuda/std/__concepts/constructible.h>
#include <cuda/std/__concepts/derived_from.h>
#include <cuda/std/__concepts/equality_comparable.h>
#include <cuda/std/__concepts/invocable.h>
#include <cuda/std/__functional/invoke.h>
#include <cuda/std/__iterator/advance.h>
#include <cuda/std/__iterator/concepts.h>
#include <cuda/std/__iterator/distance.h>
#include <cuda/std/__iterator/iterator_traits.h>
#include <cuda/std/__ranges/compressed_movable_box.h>
#include <cuda/std/__ranges/concepts.h>
#include <cuda/std/__ranges/movable_box.h>
#include <cuda/std/__type_traits/conditional.h>
#include <cuda/std/__type_traits/enable_if.h>
#include <cuda/std/__type_traits/is_assignable.h>
#include <cuda/std/__type_traits/is_nothrow_assignable.h>
#include <cuda/std/__type_traits/is_nothrow_default_constructible.h>
#include <cuda/std/__type_traits/is_nothrow_move_constructible.h>
#include <cuda/std/__type_traits/is_object.h>
#include <cuda/std/__type_traits/is_reference.h>
#include <cuda/std/__type_traits/remove_cvref.h>
#include <cuda/std/__utility/declval.h>
#include <cuda/std/__utility/forward.h>
#include <cuda/std/__utility/move.h>
#include <cuda/std/__cccl/prologue.h>
_CCCL_BEGIN_NAMESPACE_CUDA
//! @addtogroup iterators
//! @{
template <class _Fn, class _Iter>
class __transform_output_proxy
{
private:
template <class, class>
friend class transform_output_iterator;
_Iter __iter_;
_Fn& __func_;
template <class _MaybeConstFn, class _Arg>
using _Ret = ::cuda::std::invoke_result_t<_MaybeConstFn&, _Arg>;
public:
_CCCL_EXEC_CHECK_DISABLE
_CCCL_API constexpr explicit __transform_output_proxy(_Iter __iter, _Fn& __func) noexcept(
::cuda::std::is_nothrow_copy_constructible_v<_Iter>)
: __iter_(__iter)
, __func_(__func)
{}
_CCCL_HIDE_FROM_ABI __transform_output_proxy(const __transform_output_proxy&) = default;
_CCCL_HIDE_FROM_ABI __transform_output_proxy& operator=(const __transform_output_proxy&) = default;
_CCCL_HIDE_FROM_ABI __transform_output_proxy(__transform_output_proxy&&) = default;
_CCCL_HIDE_FROM_ABI __transform_output_proxy& operator=(__transform_output_proxy&&) = default;
_CCCL_EXEC_CHECK_DISABLE
_CCCL_TEMPLATE(class _Arg)
_CCCL_REQUIRES(::cuda::std::is_invocable_v<_Fn&, _Arg> //
_CCCL_AND ::cuda::std::is_assignable_v<::cuda::std::iter_reference_t<_Iter>,
::cuda::std::invoke_result_t<_Fn&, _Arg>>)
_CCCL_API constexpr __transform_output_proxy&
operator=(_Arg&& __arg) noexcept(noexcept(*__iter_ = ::cuda::std::invoke(__func_, ::cuda::std::forward<_Arg>(__arg))))
{
*__iter_ = ::cuda::std::invoke(__func_, ::cuda::std::forward<_Arg>(__arg));
return *this;
}
_CCCL_EXEC_CHECK_DISABLE
_CCCL_TEMPLATE(class _Arg)
_CCCL_REQUIRES(::cuda::std::is_invocable_v<const _Fn&, _Arg>
_CCCL_AND ::cuda::std::is_assignable_v<::cuda::std::iter_reference_t<const _Iter>,
::cuda::std::invoke_result_t<const _Fn&, _Arg>>)
_CCCL_API constexpr const __transform_output_proxy& operator=(_Arg&& __arg) const
noexcept(noexcept(*__iter_ = ::cuda::std::invoke(__func_, ::cuda::std::forward<_Arg>(__arg))))
{
*__iter_ = ::cuda::std::invoke(__func_, ::cuda::std::forward<_Arg>(__arg));
return *this;
}
};
//! @brief @c transform_output_iterator is a special kind of output iterator which transforms a value written upon
//! dereference. This iterator is useful for transforming an output from algorithms without explicitly storing the
//! intermediate result in the memory and applying subsequent transformation, thereby avoiding wasting memory capacity
//! and bandwidth. Using @c transform_output_iterator facilitates kernel fusion by deferring execution of transformation
//! until the value is written while saving both memory capacity and bandwidth.
//!
//! The following code snippet demonstrated how to create a @c transform_output_iterator which applies @c sqrtf to the
//! assigning value.
//!
//! @code
//! #include <cuda/iterator>
//! #include <thrust/device_vector.h>
//!
//! struct square_root
//! {
//! __host__ __device__
//! float operator()(float x) const
//! {
//! return cuda::std::sqrtf(x);
//! }
//! };
//!
//! int main()
//! {
//! thrust::device_vector<float> v(4);
//! cuda::transform_output_iterator iter(v.begin(), square_root());
//!
//! iter[0] = 1.0f; // stores sqrtf( 1.0f)
//! iter[1] = 4.0f; // stores sqrtf( 4.0f)
//! iter[2] = 9.0f; // stores sqrtf( 9.0f)
//! iter[3] = 16.0f; // stores sqrtf(16.0f)
//! // iter[4] is an out-of-bounds error
//!
//! v[0]; // returns 1.0f;
//! v[1]; // returns 2.0f;
//! v[2]; // returns 3.0f;
//! v[3]; // returns 4.0f;
//!
//! }
//! @endcode
template <class _Fn, class _Iter>
class transform_output_iterator
{
static_assert(::cuda::std::is_object_v<_Fn>,
"cuda::transform_output_iterator requires that _Fn is a function object");
// Not a base because then the friend operators would be ambiguous
::cuda::std::__compressed_movable_box<_Iter, _Fn> __store_;
[[nodiscard]] _CCCL_API constexpr _Iter& __iter() noexcept
{
return __store_.template __get<0>();
}
[[nodiscard]] _CCCL_API constexpr const _Iter& __iter() const noexcept
{
return __store_.template __get<0>();
}
[[nodiscard]] _CCCL_API constexpr _Fn& __func() noexcept
{
return __store_.template __get<1>();
}
[[nodiscard]] _CCCL_API constexpr const _Fn& __func() const noexcept
{
return __store_.template __get<1>();
}
public:
using iterator_concept = ::cuda::std::conditional_t<
::cuda::std::__has_random_access_traversal<_Iter>,
::cuda::std::random_access_iterator_tag,
::cuda::std::conditional_t<::cuda::std::__has_bidirectional_traversal<_Iter>,
::cuda::std::bidirectional_iterator_tag,
::cuda::std::conditional_t<::cuda::std::__has_forward_traversal<_Iter>,
::cuda::std::forward_iterator_tag,
::cuda::std::output_iterator_tag>>>;
using iterator_category = ::cuda::std::output_iterator_tag;
using difference_type = ::cuda::std::iter_difference_t<_Iter>;
using value_type = void;
using pointer = void;
using reference = void;
//! @brief Default constructs a @c transform_output_iterator with a value initialized iterator and functor
_CCCL_EXEC_CHECK_DISABLE
_CCCL_TEMPLATE(class _Iter2 = _Iter, class _Fn2 = _Fn)
_CCCL_REQUIRES(::cuda::std::default_initializable<_Iter2> _CCCL_AND ::cuda::std::default_initializable<_Fn2>)
_CCCL_API constexpr transform_output_iterator() noexcept(
::cuda::std::is_nothrow_default_constructible_v<_Iter2> && ::cuda::std::is_nothrow_default_constructible_v<_Fn2>)
: __store_()
{}
//! @brief Constructs a @c transform_output_iterator with a given iterator and output functor
//! @param __iter The iterator to transform
//! @param __func The output function to apply to the iterator on assignment
_CCCL_EXEC_CHECK_DISABLE
_CCCL_API constexpr transform_output_iterator(_Iter __iter, _Fn __func) noexcept(
::cuda::std::is_nothrow_move_constructible_v<_Iter> && ::cuda::std::is_nothrow_move_constructible_v<_Fn>)
: __store_(::cuda::std::move(__iter), ::cuda::std::move(__func))
{}
//! @brief Returns a const reference to the stored iterator
[[nodiscard]] _CCCL_API constexpr const _Iter& base() const& noexcept
{
return __iter();
}
//! @brief Extracts the stored iterator
_CCCL_EXEC_CHECK_DISABLE
[[nodiscard]] _CCCL_API constexpr _Iter base() && noexcept(::cuda::std::is_nothrow_move_constructible_v<_Iter>)
{
return ::cuda::std::move(__iter());
}
//! @brief Returns a proxy that transforms the input upon assignment
_CCCL_EXEC_CHECK_DISABLE
[[nodiscard]] _CCCL_API constexpr auto operator*() const noexcept(::cuda::std::is_nothrow_copy_constructible_v<_Iter>)
{
return __transform_output_proxy{__iter(), const_cast<_Fn&>(__func())};
}
//! @brief Returns a proxy that transforms the input upon assignment
_CCCL_EXEC_CHECK_DISABLE
[[nodiscard]] _CCCL_API constexpr auto operator*() noexcept(::cuda::std::is_nothrow_copy_constructible_v<_Iter>)
{
return __transform_output_proxy{__iter(), __func()};
}
//! @brief Subscripts the @c transform_output_iterator
//! @returns A proxy that transforms the input upon assignment storing the current iterator advanced by a given
//! @param __n The number of elements to advance by
_CCCL_EXEC_CHECK_DISABLE
_CCCL_TEMPLATE(class _Iter2 = _Iter)
_CCCL_REQUIRES(::cuda::std::__iter_can_subscript<_Iter2>)
[[nodiscard]] _CCCL_API constexpr auto operator[](difference_type __n) const
noexcept(::cuda::std::is_nothrow_copy_constructible_v<_Iter2>
&& noexcept(::cuda::std::declval<const _Iter2&>() + __n))
{
return __transform_output_proxy{__iter() + __n, const_cast<_Fn&>(__func())};
}
//! @brief Subscripts the @c transform_output_iterator
//! @returns A proxy that transforms the input upon assignment storing the current iterator advanced by a given
//! @param __n The number of elements to advance by
_CCCL_EXEC_CHECK_DISABLE
_CCCL_TEMPLATE(class _Iter2 = _Iter)
_CCCL_REQUIRES(::cuda::std::__iter_can_subscript<_Iter2>)
[[nodiscard]] _CCCL_API constexpr auto operator[](difference_type __n) noexcept(
::cuda::std::is_nothrow_copy_constructible_v<_Iter2> && noexcept(::cuda::std::declval<_Iter2&>() + __n))
{
return __transform_output_proxy{__iter() + __n, const_cast<_Fn&>(__func())};
}
//! @brief Increments the stored iterator
_CCCL_EXEC_CHECK_DISABLE
_CCCL_API constexpr transform_output_iterator& operator++() noexcept(noexcept(++::cuda::std::declval<_Iter&>()))
{
++__iter();
return *this;
}
//! @brief Increments the stored iterator
_CCCL_EXEC_CHECK_DISABLE
_CCCL_API constexpr auto operator++(int) noexcept(noexcept(++::cuda::std::declval<_Iter&>()))
{
if constexpr (::cuda::std::__has_forward_traversal<_Iter> || ::cuda::std::output_iterator<_Iter, value_type>)
{
auto __tmp = *this;
++*this;
return __tmp;
}
else
{
++__iter();
}
}
//! @brief Decrements the stored iterator
_CCCL_EXEC_CHECK_DISABLE
_CCCL_TEMPLATE(class _Iter2 = _Iter)
_CCCL_REQUIRES(::cuda::std::__iter_can_decrement<_Iter2>)
_CCCL_API constexpr transform_output_iterator& operator--() noexcept(noexcept(--::cuda::std::declval<_Iter2&>()))
{
--__iter();
return *this;
}
//! @brief Decrements the stored iterator
_CCCL_EXEC_CHECK_DISABLE
_CCCL_TEMPLATE(class _Iter2 = _Iter)
_CCCL_REQUIRES(::cuda::std::__iter_can_decrement<_Iter2>)
_CCCL_API constexpr transform_output_iterator operator--(int) noexcept(
::cuda::std::is_nothrow_copy_constructible_v<_Iter> && noexcept(--::cuda::std::declval<_Iter2&>()))
{
auto __tmp = *this;
--*this;
return __tmp;
}
//! @brief Increments the @c transform_output_iterator by a given number of elements
//! @param __n The number of elements to increment
_CCCL_EXEC_CHECK_DISABLE
_CCCL_TEMPLATE(class _Iter2 = _Iter)
_CCCL_REQUIRES(::cuda::std::__iter_can_plus_equal<_Iter2>)
_CCCL_API constexpr transform_output_iterator&
operator+=(difference_type __n) noexcept(noexcept(::cuda::std::declval<_Iter2&>() += __n))
{
__iter() += __n;
return *this;
}
//! @brief Returns a copy of a @c transform_output_iterator incremented by a given number of elements
//! @param __iter The @c transform_output_iterator to increment
//! @param __n The number of elements to increment
_CCCL_EXEC_CHECK_DISABLE
template <class _Iter2 = _Iter>
[[nodiscard]] _CCCL_API friend constexpr auto
operator+(const transform_output_iterator& __iter, difference_type __n) //
noexcept(::cuda::std::is_nothrow_copy_constructible_v<_Iter2>
&& noexcept(::cuda::std::declval<const _Iter2&>() + difference_type{}))
_CCCL_TRAILING_REQUIRES(transform_output_iterator)(::cuda::std::__iter_can_plus<_Iter2>)
{
return transform_output_iterator{__iter.__iter() + __n, __iter.__func()};
}
//! @brief Returns a copy of a @c transform_output_iterator incremented by a given number of elements
//! @param __n The number of elements to increment
//! @param __iter The @c transform_output_iterator to increment
_CCCL_EXEC_CHECK_DISABLE
template <class _Iter2 = _Iter>
[[nodiscard]] _CCCL_API friend constexpr auto
operator+(difference_type __n, const transform_output_iterator& __iter) noexcept(
::cuda::std::is_nothrow_copy_constructible_v<_Iter2>
&& noexcept(::cuda::std::declval<const _Iter2&>() + difference_type{}))
_CCCL_TRAILING_REQUIRES(transform_output_iterator)(::cuda::std::__iter_can_plus<_Iter2>)
{
return transform_output_iterator{__iter.__iter() + __n, __iter.__func()};
}
//! @brief Decrements the @c transform_output_iterator by a given number of elements
//! @param __n The number of elements to decrement
_CCCL_EXEC_CHECK_DISABLE
_CCCL_TEMPLATE(class _Iter2 = _Iter)
_CCCL_REQUIRES(::cuda::std::__iter_can_minus_equal<_Iter2>)
_CCCL_API constexpr transform_output_iterator&
operator-=(difference_type __n) noexcept(noexcept(::cuda::std::declval<_Iter2&>() -= __n))
{
__iter() -= __n;
return *this;
}
//! @brief Returns a copy of a @c transform_output_iterator decremented by a given number of elements
//! @param __iter The @c transform_output_iterator to decrement
//! @param __n The number of elements to decrement
_CCCL_EXEC_CHECK_DISABLE
template <class _Iter2 = _Iter>
[[nodiscard]] _CCCL_API friend constexpr auto
operator-(const transform_output_iterator& __iter, difference_type __n) //
noexcept(::cuda::std::is_nothrow_copy_constructible_v<_Iter2>
&& noexcept(::cuda::std::declval<const _Iter2&>() - difference_type{}))
_CCCL_TRAILING_REQUIRES(transform_output_iterator)(::cuda::std::__iter_can_minus<_Iter2>)
{
return transform_output_iterator{__iter.__iter() - __n, __iter.__func()};
}
template <class _Iter2>
static constexpr bool __can_difference =
(::cuda::std::__has_random_access_traversal<_Iter2> || ::cuda::std::sized_sentinel_for<_Iter2, _Iter2>);
template <class _Iter2>
static constexpr bool __noexcept_difference =
noexcept(::cuda::std::declval<const _Iter2&>() - ::cuda::std::declval<const _Iter2&>());
//! @brief Returns the distance between two @c transform_output_iterator
_CCCL_EXEC_CHECK_DISABLE
template <class _Iter2 = _Iter>
[[nodiscard]] _CCCL_API friend constexpr auto operator-(const transform_output_iterator& __lhs,
const transform_output_iterator& __rhs) //
noexcept(__noexcept_difference<_Iter2>) _CCCL_TRAILING_REQUIRES(difference_type)(__can_difference<_Iter2>)
{
return __lhs.__iter() - __rhs.__iter();
}
//! @brief Compares two @c transform_output_iterator for equality by comparing the stored iterators
_CCCL_EXEC_CHECK_DISABLE
template <class _Iter2 = _Iter>
[[nodiscard]] _CCCL_API friend constexpr auto
operator==(const transform_output_iterator& __lhs, const transform_output_iterator& __rhs) noexcept(
noexcept(::cuda::std::declval<const _Iter2&>() == ::cuda::std::declval<const _Iter2&>()))
_CCCL_TRAILING_REQUIRES(bool)(::cuda::std::equality_comparable<_Iter2>)
{
return __lhs.__iter() == __rhs.__iter();
}
#if _CCCL_STD_VER <= 2017
//! @brief Compares two @c transform_output_iterator for inequality by comparing the stored iterators
_CCCL_EXEC_CHECK_DISABLE
template <class _Iter2 = _Iter>
[[nodiscard]] _CCCL_API friend constexpr auto
operator!=(const transform_output_iterator& __lhs, const transform_output_iterator& __rhs) noexcept(
noexcept(::cuda::std::declval<const _Iter2&>() != ::cuda::std::declval<const _Iter2&>()))
_CCCL_TRAILING_REQUIRES(bool)(::cuda::std::equality_comparable<_Iter2>)
{
return __lhs.__iter() != __rhs.__iter();
}
#endif // _CCCL_STD_VER <= 2017
#if _LIBCUDACXX_HAS_SPACESHIP_OPERATOR()
//! @brief Three-way-compares two @c transform_output_iterator by three-way-comparing the stored iterators
_CCCL_EXEC_CHECK_DISABLE
template <class _Iter2 = _Iter>
[[nodiscard]] _CCCL_API friend constexpr auto
operator<=>(const transform_output_iterator& __lhs, const transform_output_iterator& __rhs) noexcept(
noexcept(::cuda::std::declval<const _Iter2&>() <=> ::cuda::std::declval<const _Iter2&>()))
_CCCL_TRAILING_REQUIRES(bool)(
::cuda::std::__has_random_access_traversal<_Iter2>&& ::cuda::std::three_way_comparable<_Iter2>)
{
return __lhs.__iter() <=> __rhs.__iter();
}
#else // ^^^ _LIBCUDACXX_HAS_SPACESHIP_OPERATOR() ^^^ / vvv !_LIBCUDACXX_HAS_SPACESHIP_OPERATOR() vvv
//! @brief Compares two @c transform_output_iterator for less than by comparing the stored iterators
_CCCL_EXEC_CHECK_DISABLE
template <class _Iter2 = _Iter>
[[nodiscard]] _CCCL_API friend constexpr auto
operator<(const transform_output_iterator& __lhs, const transform_output_iterator& __rhs) noexcept(
noexcept(::cuda::std::declval<const _Iter2&>() < ::cuda::std::declval<const _Iter2&>()))
_CCCL_TRAILING_REQUIRES(bool)(::cuda::std::__has_random_access_traversal<_Iter2>)
{
return __lhs.__iter() < __rhs.__iter();
}
//! @brief Compares two @c transform_output_iterator for greater than by comparing the stored iterators
_CCCL_EXEC_CHECK_DISABLE
template <class _Iter2 = _Iter>
[[nodiscard]] _CCCL_API friend constexpr auto
operator>(const transform_output_iterator& __lhs, const transform_output_iterator& __rhs) noexcept(
noexcept(::cuda::std::declval<const _Iter2&>() < ::cuda::std::declval<const _Iter2&>()))
_CCCL_TRAILING_REQUIRES(bool)(::cuda::std::__has_random_access_traversal<_Iter2>)
{
return __lhs.__iter() > __rhs.__iter();
}
//! @brief Compares two @c transform_output_iterator for less equal by comparing the stored iterators
_CCCL_EXEC_CHECK_DISABLE
template <class _Iter2 = _Iter>
[[nodiscard]] _CCCL_API friend constexpr auto
operator<=(const transform_output_iterator& __lhs, const transform_output_iterator& __rhs) noexcept(
noexcept(::cuda::std::declval<const _Iter2&>() < ::cuda::std::declval<const _Iter2&>()))
_CCCL_TRAILING_REQUIRES(bool)(::cuda::std::__has_random_access_traversal<_Iter2>)
{
return __lhs.__iter() <= __rhs.__iter();
}
//! @brief Compares two @c transform_output_iterator for greater equal by comparing the stored iterators
_CCCL_EXEC_CHECK_DISABLE
template <class _Iter2 = _Iter>
[[nodiscard]] _CCCL_API friend constexpr auto
operator>=(const transform_output_iterator& __lhs, const transform_output_iterator& __rhs) noexcept(
noexcept(::cuda::std::declval<const _Iter2&>() < ::cuda::std::declval<const _Iter2&>()))
_CCCL_TRAILING_REQUIRES(bool)(::cuda::std::__has_random_access_traversal<_Iter2>)
{
return __lhs.__iter() >= __rhs.__iter();
}
#endif // !_LIBCUDACXX_HAS_SPACESHIP_OPERATOR()
};
//! @brief Creates a @c transform_output_iterator from an iterator and an output function.
//! @param __iter The iterator of the input range
//! @param __fun The output function
//! @relates transform_output_iterator
template <class _Fn, class _Iter>
[[nodiscard]] _CCCL_API constexpr auto make_transform_output_iterator(_Iter __iter, _Fn __fun)
{
return transform_output_iterator<_Fn, _Iter>{__iter, __fun};
}
//! @}
_CCCL_END_NAMESPACE_CUDA
#ifndef _CCCL_DOXYGEN_INVOKED
# if _CCCL_HAS_HOST_STD_LIB()
_CCCL_BEGIN_NAMESPACE_STD
//! transform_output_iterator is a C++20 iterator, so it does not play well with legacy STL features like std::distance
//! To work around that specialize those functions for transform_output_iterator
template <class _Diff, class _Fn, class _Iter>
_CCCL_HOST_API constexpr void advance(::cuda::transform_output_iterator<_Fn, _Iter>& __iter, _Diff __diff)
{
::cuda::std::advance(__iter, ::cuda::std::move(__diff));
}
template <class _Fn, class _Iter>
[[nodiscard]] _CCCL_HOST_API constexpr ::cuda::std::iter_difference_t<_Iter>
distance(::cuda::transform_output_iterator<_Fn, _Iter> __first, ::cuda::transform_output_iterator<_Fn, _Iter> __last)
{
return ::cuda::std::distance(::cuda::std::move(__first), ::cuda::std::move(__last));
}
template <class _Fn, class _Iter>
[[nodiscard]] _CCCL_HOST_API constexpr ::cuda::transform_output_iterator<_Fn, _Iter>
next(::cuda::transform_output_iterator<_Fn, _Iter> __iter, ::cuda::std::iter_difference_t<_Iter> __n = 1)
{
_CCCL_ASSERT(__n >= 0 || ::cuda::std::__has_bidirectional_traversal<_Iter>,
"Attempt to std::next(it, n) with negative n on a non-bidirectional iterator");
::cuda::std::advance(__iter, __n);
return __iter;
}
template <class _Fn, class _Iter>
[[nodiscard]] _CCCL_HOST_API constexpr ::cuda::transform_output_iterator<_Fn, _Iter>
prev(::cuda::transform_output_iterator<_Fn, _Iter> __iter, ::cuda::std::iter_difference_t<_Iter> __n = 1)
{
_CCCL_ASSERT(__n <= 0 || ::cuda::std::__has_bidirectional_traversal<_Iter>,
"Attempt to std::prev(it, +n) on a non-bidi iterator");
::cuda::std::advance(__iter, -__n);
return __iter;
}
_CCCL_END_NAMESPACE_STD
# endif // _CCCL_HAS_HOST_STD_LIB()
#endif // _CCCL_DOXYGEN_INVOKED
#include <cuda/std/__cccl/epilogue.h>
#endif // _CUDA___ITERATOR_TRANSFORM_OUTPUT_ITERATOR_H

View File

@@ -0,0 +1,282 @@
// -*- 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
//
//===----------------------------------------------------------------------===//
#ifndef _CUDA___ITERATOR_ZIP_COMMON_H
#define _CUDA___ITERATOR_ZIP_COMMON_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/__fwd/iterator.h>
#include <cuda/std/__algorithm/ranges_min_element.h>
#include <cuda/std/__concepts/constructible.h>
#include <cuda/std/__fwd/pair.h>
#include <cuda/std/__fwd/tuple.h>
#include <cuda/std/__iterator/concepts.h>
#include <cuda/std/__iterator/iter_move.h>
#include <cuda/std/__iterator/iter_swap.h>
#include <cuda/std/__iterator/iterator_traits.h>
#include <cuda/std/__iterator/readable_traits.h>
#include <cuda/std/__tuple_dir/get.h>
#include <cuda/std/__tuple_dir/tuple_element.h>
#include <cuda/std/__tuple_dir/tuple_size.h>
#include <cuda/std/__type_traits/is_nothrow_default_constructible.h>
#include <cuda/std/__type_traits/is_nothrow_move_constructible.h>
#include <cuda/std/__type_traits/remove_cvref.h>
#include <cuda/std/__type_traits/remove_reference.h>
#include <cuda/std/__type_traits/void_t.h>
#include <cuda/std/__utility/declval.h>
#include <cuda/std/__utility/integer_sequence.h>
#include <cuda/std/__cccl/prologue.h>
_CCCL_BEGIN_NAMESPACE_CUDA
template <class... _Iterators>
struct __zip_iter_constraints
{
static constexpr bool __all_forward = (::cuda::std::__has_forward_traversal<_Iterators> && ...);
static constexpr bool __all_bidirectional = (::cuda::std::__has_bidirectional_traversal<_Iterators> && ...);
static constexpr bool __all_random_access = (::cuda::std::__has_random_access_traversal<_Iterators> && ...);
static constexpr bool __all_equality_comparable = (::cuda::std::equality_comparable<_Iterators> && ...);
#if _LIBCUDACXX_HAS_SPACESHIP_OPERATOR()
static constexpr bool __all_three_way_comparable = (::cuda::std::three_way_comparable<_Iterators> && ...);
#endif // _LIBCUDACXX_HAS_SPACESHIP_OPERATOR()
// Our C++17 iterators sometimes do not satisfy `sized_sentinel_for` but they should all be random_access
static constexpr bool __all_sized_sentinel =
(::cuda::std::sized_sentinel_for<_Iterators, _Iterators> && ...) || __all_random_access;
static constexpr bool __all_nothrow_iter_movable =
(noexcept(::cuda::std::ranges::__iter_move_cpo{}(::cuda::std::declval<const _Iterators&>())) && ...)
&& (::cuda::std::is_nothrow_move_constructible_v<::cuda::std::iter_rvalue_reference_t<_Iterators>> && ...);
static constexpr bool __all_indirectly_swappable = (::cuda::std::indirectly_swappable<_Iterators> && ...);
static constexpr bool __all_noexcept_swappable = (::cuda::std::__noexcept_swappable<_Iterators> && ...);
static constexpr bool __all_nothrow_move_constructible =
(::cuda::std::is_nothrow_move_constructible_v<_Iterators> && ...);
static constexpr bool __all_default_initializable = (::cuda::std::default_initializable<_Iterators> && ...);
static constexpr bool __all_nothrow_default_constructible =
(::cuda::std::is_nothrow_default_constructible_v<_Iterators> && ...);
};
template <class... _Iterators>
[[nodiscard]] _CCCL_API _CCCL_CONSTEVAL auto __get_zip_iterator_concept()
{
using _Constraints = __zip_iter_constraints<_Iterators...>;
if constexpr (_Constraints::__all_random_access)
{
return ::cuda::std::random_access_iterator_tag();
}
else if constexpr (_Constraints::__all_bidirectional)
{
return ::cuda::std::bidirectional_iterator_tag();
}
else if constexpr (_Constraints::__all_forward)
{
return ::cuda::std::forward_iterator_tag();
}
else
{
return ::cuda::std::input_iterator_tag();
}
}
//! @note Not static functions because nvc++ sometimes has issues with class static functions in device code
struct __zip_op_star
{
template <class... _Iterators>
using reference = ::cuda::std::tuple<::cuda::std::iter_reference_t<_Iterators>...>;
_CCCL_EXEC_CHECK_DISABLE
template <class... _Iterators>
[[nodiscard]] _CCCL_API constexpr auto operator()(const _Iterators&... __iters) const
noexcept(noexcept(reference<_Iterators...>{*__iters...}))
{
return reference<_Iterators...>{*__iters...};
}
};
struct __zip_op_increment
{
_CCCL_EXEC_CHECK_DISABLE
template <class... _Iterators>
_CCCL_API constexpr void operator()(_Iterators&... __iters) const noexcept(noexcept(((void) ++__iters, ...)))
{
((void) ++__iters, ...);
}
};
struct __zip_op_decrement
{
_CCCL_EXEC_CHECK_DISABLE
template <class... _Iterators>
_CCCL_API constexpr void operator()(_Iterators&... __iters) const noexcept(noexcept(((void) --__iters, ...)))
{
((void) --__iters, ...);
}
};
struct __zip_iter_move
{
template <class... _Iterators>
using __iter_move_ret = ::cuda::std::tuple<::cuda::std::iter_rvalue_reference_t<_Iterators>...>;
_CCCL_EXEC_CHECK_DISABLE
template <class... _Iterators>
[[nodiscard]] _CCCL_API constexpr auto operator()(const _Iterators&... __iters) const
noexcept(noexcept(__iter_move_ret<_Iterators...>{::cuda::std::ranges::__iter_move_cpo{}(__iters)...}))
{
return __iter_move_ret<_Iterators...>{::cuda::std::ranges::__iter_move_cpo{}(__iters)...};
}
};
struct __zip_op_eq
{
// Extra level of indirection needed because GCC7 and older clang don't allow you to use
// member functions in noexcept() clauses. We also can't use
// __is_cpp17_nothrow_equality_comparable_v because the tuple-like type passed to these
// functions might not implement operator==().
template <class _Tuple1, class _Tuple2, ::cuda::std::size_t... _Indices>
[[nodiscard]] _CCCL_API static constexpr bool
__do_it(const _Tuple1& __tuple1, const _Tuple2& __tuple2, ::cuda::std::index_sequence<_Indices...>) noexcept(
noexcept(((::cuda::std::get<_Indices>(__tuple1) == ::cuda::std::get<_Indices>(__tuple2)) || ...)))
{
return ((::cuda::std::get<_Indices>(__tuple1) == ::cuda::std::get<_Indices>(__tuple2)) || ...);
}
template <class _Tuple1, class _Tuple2, ::cuda::std::size_t... _Indices>
[[nodiscard]] _CCCL_API constexpr bool
operator()(const _Tuple1& __tuple1, const _Tuple2& __tuple2, ::cuda::std::index_sequence<_Indices...> __seq) const
noexcept(noexcept(::cuda::__zip_op_eq::__do_it(__tuple1, __tuple2, __seq)))
{
return ::cuda::__zip_op_eq::__do_it(__tuple1, __tuple2, __seq);
}
template <class _Tuple1, class _Tuple2>
[[nodiscard]] _CCCL_API constexpr bool operator()(const _Tuple1& __tuple1, const _Tuple2& __tuple2) const
noexcept(noexcept(::cuda::__zip_op_eq::__do_it(
__tuple1,
__tuple2,
::cuda::std::make_index_sequence<::cuda::std::tuple_size_v<::cuda::std::remove_cvref_t<_Tuple1>>>{})))
{
return ::cuda::__zip_op_eq::__do_it(
__tuple1,
__tuple2,
::cuda::std::make_index_sequence<::cuda::std::tuple_size_v<::cuda::std::remove_cvref_t<_Tuple1>>>{});
}
};
template <class _Tp, class _Up>
inline constexpr bool __nothrow_distance =
noexcept(::cuda::std::declval<const _Tp&>() - ::cuda::std::declval<const _Up&>());
template <class _Diff>
struct __zip_op_minus
{
struct __op_comp_abs
{
// abs in cstdlib is not constexpr
_CCCL_EXEC_CHECK_DISABLE
[[nodiscard]] _CCCL_API static constexpr _Diff __abs(_Diff __t) noexcept(noexcept(__t < 0 ? -__t : __t))
{
return __t < 0 ? -__t : __t;
}
_CCCL_EXEC_CHECK_DISABLE
[[nodiscard]] _CCCL_API constexpr bool operator()(const _Diff& __x, const _Diff& __y) const
noexcept(noexcept(__op_comp_abs::__abs(__x) < __op_comp_abs::__abs(__y)))
{
return __op_comp_abs::__abs(__x) < __op_comp_abs::__abs(__y);
}
};
// Extra level of indirection needed because GCC7 and older clang don't allow you to use
// member functions in noexcept() clauses.
_CCCL_EXEC_CHECK_DISABLE
template <class _Tuple1, class _Tuple2, ::cuda::std::size_t _Zero, ::cuda::std::size_t... _Indices>
[[nodiscard]] _CCCL_API static constexpr _Diff
__do_it(const _Tuple1& __tuple1, const _Tuple2& __tuple2, ::cuda::std::index_sequence<_Zero, _Indices...>) noexcept(
__nothrow_distance<::cuda::std::tuple_element_t<_Zero, _Tuple1>, ::cuda::std::tuple_element_t<_Zero, _Tuple2>>
&& (__nothrow_distance<::cuda::std::tuple_element_t<_Indices, _Tuple1>,
::cuda::std::tuple_element_t<_Indices, _Tuple2>>
&& ...))
{
const _Diff __first = ::cuda::std::get<0>(__tuple1) - ::cuda::std::get<0>(__tuple2);
if (__first == 0)
{
return __first;
}
const _Diff __temp[] = {__first, ::cuda::std::get<_Indices>(__tuple1) - ::cuda::std::get<_Indices>(__tuple2)...};
return *::cuda::std::ranges::__min_element_cpo{}(__temp, __op_comp_abs{});
}
_CCCL_EXEC_CHECK_DISABLE
template <class _Tuple1, class _Tuple2, ::cuda::std::size_t... _Indices>
[[nodiscard]] _CCCL_API constexpr _Diff
operator()(const _Tuple1& __tuple1, const _Tuple2& __tuple2, ::cuda::std::index_sequence<_Indices...> __seq) const
noexcept(noexcept(__zip_op_minus::__do_it(__tuple1, __tuple2, __seq)))
{
return __zip_op_minus::__do_it(__tuple1, __tuple2, __seq);
}
_CCCL_EXEC_CHECK_DISABLE
template <class _Tuple1, class _Tuple2>
[[nodiscard]] _CCCL_API constexpr _Diff operator()(const _Tuple1& __tuple1, const _Tuple2& __tuple2) const
noexcept(noexcept(__zip_op_minus::__do_it(
__tuple1,
__tuple2,
::cuda::std::make_index_sequence<::cuda::std::tuple_size_v<::cuda::std::remove_cvref_t<_Tuple1>>>{})))
{
return __zip_op_minus::__do_it(
__tuple1,
__tuple2,
::cuda::std::make_index_sequence<::cuda::std::tuple_size_v<::cuda::std::remove_cvref_t<_Tuple1>>>{});
}
};
// We need this to make proxy iterators work because those might not have a working `iter_value_t`
template <class _Iter, class = void>
struct __zip_maybe_proxy_helper
{
using reference = decltype(*::cuda::std::declval<_Iter>());
using value_type = ::cuda::std::remove_reference_t<reference>;
};
template <class _Iter>
struct __zip_maybe_proxy_helper<_Iter, ::cuda::std::void_t<::cuda::std::iter_value_t<_Iter>>>
{
using reference = ::cuda::std::iter_reference_t<_Iter>;
using value_type = ::cuda::std::iter_value_t<_Iter>;
};
template <class _Iter>
using __zip_maybe_proxy_reference_t = typename __zip_maybe_proxy_helper<_Iter>::reference;
template <class _Iter>
using __zip_maybe_proxy_value_type_t = typename __zip_maybe_proxy_helper<_Iter>::value_type;
_CCCL_END_NAMESPACE_CUDA
#include <cuda/std/__cccl/epilogue.h>
#endif // _CUDA___ITERATOR_ZIP_COMMON_H

View File

@@ -0,0 +1,125 @@
// -*- 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
//
//===----------------------------------------------------------------------===//
#ifndef _CUDA___ITERATOR_ZIP_FUNCTION_H
#define _CUDA___ITERATOR_ZIP_FUNCTION_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/__fwd/iterator.h>
#include <cuda/std/__concepts/constructible.h>
#include <cuda/std/__functional/invoke.h>
#include <cuda/std/__type_traits/is_nothrow_copy_constructible.h>
#include <cuda/std/__type_traits/is_nothrow_default_constructible.h>
#include <cuda/std/__type_traits/is_nothrow_move_constructible.h>
#include <cuda/std/__utility/declval.h>
#include <cuda/std/__utility/forward.h>
#include <cuda/std/__utility/move.h>
#include <cuda/std/__utility/pair.h>
#include <cuda/std/tuple>
#include <cuda/std/__cccl/prologue.h>
_CCCL_BEGIN_NAMESPACE_CUDA
//! @addtogroup iterators
//! @{
//! @brief Adaptor that transforms a functor taking arguments of types @c Ts... into one accepting a @c tuple<Ts...>
//! @tparam _Fn The functor to wrap
//! @relates zip_iterator
template <class _Fn>
class zip_function
{
private:
_Fn __fun_;
public:
//! @brief default construct a zip_function
_CCCL_EXEC_CHECK_DISABLE
_CCCL_TEMPLATE(class _Fn2 = _Fn)
_CCCL_REQUIRES(::cuda::std::default_initializable<_Fn2>)
_CCCL_API constexpr zip_function() noexcept(::cuda::std::is_nothrow_default_constructible_v<_Fn2>)
: __fun_()
{}
//! @brief construct a zip_function from a functor
_CCCL_EXEC_CHECK_DISABLE
_CCCL_API constexpr zip_function(const _Fn& __fun) noexcept(::cuda::std::is_nothrow_copy_constructible_v<_Fn>)
: __fun_(__fun)
{}
//! @brief construct a zip_function from a functor
_CCCL_EXEC_CHECK_DISABLE
_CCCL_API constexpr zip_function(_Fn&& __fun) noexcept(::cuda::std::is_nothrow_move_constructible_v<_Fn>)
: __fun_(::cuda::std::move(__fun))
{}
template <class _Fn2, class _Tuple>
static constexpr bool __is_nothrow_invocable =
noexcept(::cuda::std::apply(::cuda::std::declval<_Fn2>(), ::cuda::std::declval<_Tuple>()));
#ifndef _CCCL_DOXYGEN_INVOKED // Doxygen interprets this as a duplicated function
//! @brief Applies a tuple to the stored functor
//! @param __tuple The tuple of arguments to be passed
_CCCL_EXEC_CHECK_DISABLE
_CCCL_TEMPLATE(class _Tuple)
_CCCL_REQUIRES(::cuda::std::__can_apply<const _Fn&, _Tuple>)
[[nodiscard]] _CCCL_API constexpr decltype(auto) operator()(_Tuple&& __tuple) const
noexcept(__is_nothrow_invocable<const _Fn&, _Tuple>)
{
return ::cuda::std::apply(__fun_, ::cuda::std::forward<_Tuple>(__tuple));
}
//! @brief Applies a tuple to the stored functor
_CCCL_EXEC_CHECK_DISABLE
_CCCL_TEMPLATE(class _Tuple)
_CCCL_REQUIRES(::cuda::std::__can_apply<_Fn&, _Tuple>)
[[nodiscard]] _CCCL_API constexpr decltype(auto)
operator()(_Tuple&& __tuple) noexcept(__is_nothrow_invocable<_Fn&, _Tuple>)
{
return ::cuda::std::apply(__fun_, ::cuda::std::forward<_Tuple>(__tuple));
}
#endif // !_CCCL_DOXYGEN_INVOKED
[[nodiscard]] _CCCL_API constexpr _Fn& __fun() noexcept
{
return __fun_;
}
[[nodiscard]] _CCCL_API constexpr const _Fn& __fun() const noexcept
{
return __fun_;
}
};
//! @brief Creates a @c zip_function from a function
//! @tparam _Fn The functor to wrap
//! @relates zip_iterator
template <class _Fn>
_CCCL_API constexpr zip_function<::cuda::std::decay_t<_Fn>> make_zip_function(_Fn&& __fun)
{
return zip_function<::cuda::std::decay_t<_Fn>>{::cuda::std::forward<_Fn>(__fun)};
}
//! @}
_CCCL_END_NAMESPACE_CUDA
#include <cuda/std/__cccl/epilogue.h>
#endif // _CUDA___ITERATOR_ZIP_FUNCTION_H

View File

@@ -0,0 +1,550 @@
// -*- 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
//
//===----------------------------------------------------------------------===//
#ifndef _CUDA___ITERATOR_ZIP_ITERATOR_H
#define _CUDA___ITERATOR_ZIP_ITERATOR_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/__fwd/iterator.h>
#include <cuda/std/__algorithm/ranges_min_element.h>
#if _LIBCUDACXX_HAS_SPACESHIP_OPERATOR()
# include <cuda/std/__compare/three_way_comparable.h>
#endif // _LIBCUDACXX_HAS_SPACESHIP_OPERATOR()
#include <cuda/__iterator/zip_common.h>
#include <cuda/std/__concepts/convertible_to.h>
#include <cuda/std/__concepts/equality_comparable.h>
#include <cuda/std/__functional/invoke.h>
#include <cuda/std/__functional/operations.h>
#include <cuda/std/__iterator/advance.h>
#include <cuda/std/__iterator/concepts.h>
#include <cuda/std/__iterator/distance.h>
#include <cuda/std/__iterator/incrementable_traits.h>
#include <cuda/std/__iterator/iter_move.h>
#include <cuda/std/__iterator/iter_swap.h>
#include <cuda/std/__iterator/iterator_traits.h>
#include <cuda/std/__ranges/concepts.h>
#include <cuda/std/__type_traits/common_type.h>
#include <cuda/std/__type_traits/make_unsigned.h>
#include <cuda/std/__type_traits/remove_cvref.h>
#include <cuda/std/__utility/forward.h>
#include <cuda/std/__utility/integer_sequence.h>
#include <cuda/std/__utility/move.h>
#include <cuda/std/tuple>
#include <cuda/std/__cccl/prologue.h>
_CCCL_BEGIN_NAMESPACE_CUDA
//! @addtogroup iterators
//! @{
struct __zv_iter_category_base_none
{};
struct __zv_iter_category_base_tag
{
using iterator_category = ::cuda::std::input_iterator_tag;
};
template <class... _Iterators>
using __zv_iter_category_base =
::cuda::std::conditional_t<__zip_iter_constraints<_Iterators...>::__all_forward,
__zv_iter_category_base_tag,
__zv_iter_category_base_none>;
//! @brief @c zip_iterator is an iterator which represents a @c tuple of iterators. This iterator is useful for creating
//! a virtual array of structures while achieving the same performance and bandwidth as the structure of arrays idiom.
//! @c zip_iterator also facilitates kernel fusion by providing a convenient means of amortizing the execution of the
//! same operation over multiple ranges.
//!
//! The following code snippet demonstrates how to create a @c zip_iterator which represents the result of "zipping"
//! multiple ranges together.
//!
//! @code
//! #include <cuda/iterator>
//! #include <thrust/device_vector.h>
//!
//! thrust::device_vector<int> int_v{0, 1, 2};
//! thrust::device_vector<float> float_v{0.0f, 1.0f, 2.0f};
//! thrust::device_vector<char> char_v{'a', 'b', 'c'};
//!
//! cuda::zip_iterator iter{int_v.begin(), float_v.begin(), char_v.begin()};
//!
//! *iter; // returns (0, 0.0f, 'a')
//! iter[0]; // returns (0, 0.0f, 'a')
//! iter[1]; // returns (1, 1.0f, 'b')
//! iter[2]; // returns (2, 2.0f, 'c')
//!
//! cuda::std::get<0>(iter[2]); // returns 2
//! cuda::std::get<1>(iter[0]); // returns 0.0f
//! cuda::std::get<2>(iter[1]); // returns 'b'
//!
//! // iter[3] is an out-of-bounds error
//! @endcode
//!
//! This example shows how to use @c zip_iterator to copy multiple ranges with a single call to @c thrust::copy.
//!
//! @code
//! #include <cuda/iterator>
//! #include <thrust/device_vector.h>
//!
//! int main()
//! {
//! thrust::device_vector<int> int_in{0, 1, 2}, int_out(3);
//! thrust::device_vector<float> float_in{0.0f, 10.0f, 20.0f}, float_out(3);
//!
//! thrust::copy(cuda::zip_iterator{int_in.begin(), float_in.begin()},
//! cuda::zip_iterator{int_in.end(), float_in.end()},
//! cuda::zip_iterator{int_out.begin(),float_out.begin()});
//!
//! // int_out is now [0, 1, 2]
//! // float_out is now [0.0f, 10.0f, 20.0f]
//!
//! return 0;
//! }
//! @endcode
template <class... _Iterators>
class zip_iterator : public __zv_iter_category_base<_Iterators...>
{
::cuda::std::tuple<_Iterators...> __current_;
template <class...>
friend class zip_iterator;
template <class _Fn>
_CCCL_API static constexpr auto
__zip_apply(const _Fn& __fun,
const ::cuda::std::tuple<_Iterators...>& __tuple1,
const ::cuda::std::tuple<_Iterators...>& __tuple2) //
noexcept(noexcept(__fun(__tuple1, __tuple2, ::cuda::std::make_index_sequence<sizeof...(_Iterators)>())))
{
return __fun(__tuple1, __tuple2, ::cuda::std::make_index_sequence<sizeof...(_Iterators)>());
}
public:
//! @brief Default-constructs a @c zip_iterator by defaulting all stored iterators
_CCCL_HIDE_FROM_ABI zip_iterator() = default;
//! @brief Constructs a @c zip_iterator from a tuple of iterators
//! @param __iters A tuple of iterators
_CCCL_API constexpr explicit zip_iterator(::cuda::std::tuple<_Iterators...> __iters)
: __current_(::cuda::std::move(__iters))
{}
//! @brief Constructs a @c zip_iterator from a tuple of iterators
//! @param __iters A tuple of iterators
_CCCL_TEMPLATE(size_t _NumIterators = sizeof...(_Iterators))
_CCCL_REQUIRES((_NumIterators == 2))
_CCCL_API constexpr explicit zip_iterator(::cuda::std::tuple<_Iterators...> __iters)
: __current_(::cuda::std::get<0>(::cuda::std::move(__iters)), ::cuda::std::get<1>(::cuda::std::move(__iters)))
{}
//! @brief Constructs a @c zip_iterator from variadic set of iterators
//! @param __iters The input iterators
_CCCL_API constexpr explicit zip_iterator(_Iterators... __iters)
: __current_(::cuda::std::move(__iters)...)
{}
using iterator_concept = decltype(__get_zip_iterator_concept<_Iterators...>());
using value_type = ::cuda::std::tuple<__zip_maybe_proxy_value_type_t<_Iterators>...>;
using reference = ::cuda::std::tuple<__zip_maybe_proxy_reference_t<_Iterators>...>;
using difference_type = ::cuda::std::common_type_t<::cuda::std::iter_difference_t<_Iterators>...>;
// Those are technically not to spec, but pre-ranges iterator_traits do not work properly with iterators that do not
// define all 5 aliases, see https://en.cppreference.com/w/cpp/iterator/iterator_traits.html
using pointer = void;
template <class... _OtherIters>
static constexpr bool __all_convertible =
(::cuda::std::convertible_to<_OtherIters, _Iterators> && ...)
&& !(::cuda::std::is_same_v<_Iterators, _OtherIters> && ...);
//! @brief Converts a different @c zip_iterator
//! @param __iter The other @c zip_iterator
_CCCL_TEMPLATE(class... _OtherIters)
_CCCL_REQUIRES((sizeof...(_OtherIters) == sizeof...(_Iterators)) _CCCL_AND __all_convertible<_OtherIters...>)
_CCCL_API constexpr zip_iterator(zip_iterator<_OtherIters...> __iter)
: __current_(::cuda::std::move(__iter.__current_))
{}
//! @brief Dereferences the @c zip_iterator
//! @returns A tuple of references obtained by referencing every stored iterator
[[nodiscard]] _CCCL_API constexpr auto operator*() const
noexcept(noexcept(::cuda::std::apply(__zip_op_star{}, __current_)))
{
return ::cuda::std::apply(__zip_op_star{}, __current_);
}
struct __zip_op_index
{
difference_type __n;
_CCCL_EXEC_CHECK_DISABLE
[[nodiscard]] _CCCL_API constexpr reference operator()(const _Iterators&... __iters) const
noexcept(noexcept(reference{__iters[::cuda::std::iter_difference_t<_Iterators>(__n)]...}))
{
return reference{__iters[::cuda::std::iter_difference_t<_Iterators>(__n)]...};
}
};
//! @brief Subscripts the @c zip_iterator with an offset
//! @param __n The additional offset
//! @returns A tuple of references obtained by subscripting every stored iterator
_CCCL_TEMPLATE(class _Constraints = __zip_iter_constraints<_Iterators...>)
_CCCL_REQUIRES(_Constraints::__all_random_access)
_CCCL_API constexpr auto operator[](difference_type __n) const
noexcept(noexcept(::cuda::std::apply(__zip_op_index{__n}, __current_)))
{
return ::cuda::std::apply(__zip_op_index{__n}, __current_);
}
//! @brief Increments all stored iterators
_CCCL_API constexpr zip_iterator& operator++() noexcept(noexcept(::cuda::std::apply(__zip_op_increment{}, __current_)))
{
::cuda::std::apply(__zip_op_increment{}, __current_);
return *this;
}
//! @brief Increments all stored iterators
//! @returns A copy of the original @c zip_iterator if possible
_CCCL_API constexpr auto operator++(int)
{
if constexpr (__zip_iter_constraints<_Iterators...>::__all_forward)
{
auto __tmp = *this;
++*this;
return __tmp;
}
else
{
++*this;
}
}
//! @brief Decrements all stored iterators
_CCCL_TEMPLATE(class _Constraints = __zip_iter_constraints<_Iterators...>)
_CCCL_REQUIRES(_Constraints::__all_bidirectional)
_CCCL_API constexpr zip_iterator& operator--() noexcept(noexcept(::cuda::std::apply(__zip_op_decrement{}, __current_)))
{
::cuda::std::apply(__zip_op_decrement{}, __current_);
return *this;
}
//! @brief Decrements all stored iterators
_CCCL_TEMPLATE(class _Constraints = __zip_iter_constraints<_Iterators...>)
_CCCL_REQUIRES(_Constraints::__all_bidirectional)
_CCCL_API constexpr zip_iterator operator--(int)
{
auto __tmp = *this;
--*this;
return __tmp;
}
struct __zip_op_pe
{
difference_type __n;
_CCCL_EXEC_CHECK_DISABLE
_CCCL_API constexpr void operator()(_Iterators&... __iters) const
noexcept(noexcept(((void) (__iters += ::cuda::std::iter_difference_t<_Iterators>(__n)), ...)))
{
((void) (__iters += ::cuda::std::iter_difference_t<_Iterators>(__n)), ...);
}
};
//! @brief Increments all stored iterators by a given number of elements
//! @param __n The number of elements to increment
_CCCL_TEMPLATE(class _Constraints = __zip_iter_constraints<_Iterators...>)
_CCCL_REQUIRES(_Constraints::__all_random_access)
_CCCL_API constexpr zip_iterator&
operator+=(difference_type __n) noexcept(noexcept(::cuda::std::apply(__zip_op_pe{__n}, __current_)))
{
::cuda::std::apply(__zip_op_pe{__n}, __current_);
return *this;
}
struct __zip_op_me
{
difference_type __n;
_CCCL_EXEC_CHECK_DISABLE
_CCCL_API constexpr void operator()(_Iterators&... __iters) const
noexcept(noexcept(((void) (__iters -= ::cuda::std::iter_difference_t<_Iterators>(__n)), ...)))
{
((void) (__iters -= ::cuda::std::iter_difference_t<_Iterators>(__n)), ...);
}
};
//! @brief Decrements all stored iterators by a given number of elements
//! @param __n The number of elements to decrement
_CCCL_TEMPLATE(class _Constraints = __zip_iter_constraints<_Iterators...>)
_CCCL_REQUIRES(_Constraints::__all_random_access)
_CCCL_API constexpr zip_iterator&
operator-=(difference_type __n) noexcept(noexcept(::cuda::std::apply(__zip_op_me{__n}, __current_)))
{
::cuda::std::apply(__zip_op_me{__n}, __current_);
return *this;
}
//! @brief Returns a copy of a @c zip_iterator incremented by a given number of elements
//! @param __iter The @c zip_iterator to increment
//! @param __n The number of elements to increment
template <class _Constraints = __zip_iter_constraints<_Iterators...>>
_CCCL_API friend constexpr auto operator+(const zip_iterator& __iter, difference_type __n)
_CCCL_TRAILING_REQUIRES(zip_iterator)(_Constraints::__all_random_access)
{
auto __rhs = __iter;
__rhs += __n;
return __rhs;
}
//! @brief Returns a copy of a @c zip_iterator incremented by a given number of elements
//! @param __n The number of elements to increment
//! @param __iter The @c zip_iterator to increment
template <class _Constraints = __zip_iter_constraints<_Iterators...>>
_CCCL_API friend constexpr auto operator+(difference_type __n, const zip_iterator& __iter)
_CCCL_TRAILING_REQUIRES(zip_iterator)(_Constraints::__all_random_access)
{
return __iter + __n;
}
//! @brief Returns a copy of a @c zip_iterator decremented by a given number of elements
//! @param __n The number of elements to decrement
//! @param __iter The @c zip_iterator to decrement
template <class _Constraints = __zip_iter_constraints<_Iterators...>>
_CCCL_API friend constexpr auto operator-(const zip_iterator& __iter, difference_type __n)
_CCCL_TRAILING_REQUIRES(zip_iterator)(_Constraints::__all_random_access)
{
auto __rhs = __iter;
__rhs -= __n;
return __rhs;
}
//! @brief Returns the distance between two @c zip_iterators
//! @returns The minimal distance between any of the stored iterators
template <class _Constraints = __zip_iter_constraints<_Iterators...>>
_CCCL_API friend constexpr auto operator-(const zip_iterator& __n, const zip_iterator& __y)
_CCCL_TRAILING_REQUIRES(difference_type)(_Constraints::__all_sized_sentinel)
{
return __zip_apply(__zip_op_minus<difference_type>{}, __n.__current_, __y.__current_);
}
//! @brief Compares two @c zip_iterator for equality by comparing the tuple of stored iterators
template <class _Constraints = __zip_iter_constraints<_Iterators...>>
_CCCL_API friend constexpr auto operator==(const zip_iterator& __n, const zip_iterator& __y)
_CCCL_TRAILING_REQUIRES(bool)(_Constraints::__all_equality_comparable)
{
if constexpr (_Constraints::__all_bidirectional)
{
return __n.__current_ == __y.__current_;
}
else
{
return __zip_apply(__zip_op_eq{}, __n.__current_, __y.__current_);
}
}
#if _CCCL_STD_VER <= 2017
//! @brief Compares two @c zip_iterator for inequality by comparing the tuple of stored iterators
template <class _Constraints = __zip_iter_constraints<_Iterators...>>
_CCCL_API friend constexpr auto operator!=(const zip_iterator& __n, const zip_iterator& __y)
_CCCL_TRAILING_REQUIRES(bool)(_Constraints::__all_equality_comparable)
{
if constexpr (_Constraints::__all_bidirectional)
{
return __n.__current_ != __y.__current_;
}
else
{
return !__zip_apply(__zip_op_eq{}, __n.__current_, __y.__current_);
}
}
#endif // _CCCL_STD_VER <= 2017
#if _LIBCUDACXX_HAS_SPACESHIP_OPERATOR()
//! @brief Three-way compares two @c zip_iterator by comparing the tuple of stored iterators
template <class _Constraints = __zip_iter_constraints<_Iterators...>>
_CCCL_API friend constexpr auto operator<=>(const zip_iterator& __n, const zip_iterator& __y)
_CCCL_TRAILING_REQUIRES(bool)(_Constraints::__all_random_access&& _Constraints::__all_three_way_comparable)
{
return __n.__current_ <=> __y.__current_;
}
#else // ^^^ _LIBCUDACXX_HAS_SPACESHIP_OPERATOR() ^^^ / vvv !_LIBCUDACXX_HAS_SPACESHIP_OPERATOR() vvv
//! @brief Compares two @c zip_iterator for less than by comparing the tuple of stored iterators
template <class _Constraints = __zip_iter_constraints<_Iterators...>>
_CCCL_API friend constexpr auto operator<(const zip_iterator& __n, const zip_iterator& __y)
_CCCL_TRAILING_REQUIRES(bool)(_Constraints::__all_random_access)
{
return __n.__current_ < __y.__current_;
}
//! @brief Compares two @c zip_iterator for greater than by comparing the tuple of stored iterators
template <class _Constraints = __zip_iter_constraints<_Iterators...>>
_CCCL_API friend constexpr auto operator>(const zip_iterator& __n, const zip_iterator& __y)
_CCCL_TRAILING_REQUIRES(bool)(_Constraints::__all_random_access)
{
return __y < __n;
}
//! @brief Compares two @c zip_iterator for less equal by comparing the tuple of stored iterators
template <class _Constraints = __zip_iter_constraints<_Iterators...>>
_CCCL_API friend constexpr auto operator<=(const zip_iterator& __n, const zip_iterator& __y)
_CCCL_TRAILING_REQUIRES(bool)(_Constraints::__all_random_access)
{
return !(__y < __n);
}
//! @brief Compares two @c zip_iterator for greater equal by comparing the tuple of stored iterators
template <class _Constraints = __zip_iter_constraints<_Iterators...>>
_CCCL_API friend constexpr auto operator>=(const zip_iterator& __n, const zip_iterator& __y)
_CCCL_TRAILING_REQUIRES(bool)(_Constraints::__all_random_access)
{
return !(__n < __y);
}
#endif // !_LIBCUDACXX_HAS_SPACESHIP_OPERATOR()
//! @brief Applies `iter_move` by applying it to all stored iterators
// MSVC falls over its feet if this is not a template
template <class _Constraints = __zip_iter_constraints<_Iterators...>>
_CCCL_API friend constexpr auto
iter_move(const zip_iterator& __iter) noexcept(_Constraints::__all_nothrow_iter_movable)
{
return ::cuda::std::apply(__zip_iter_move{}, __iter.__current_);
}
struct __zip_op_iter_swap
{
template <size_t... _Indices>
_CCCL_API constexpr void operator()(const ::cuda::std::tuple<_Iterators...>& __iters1,
const ::cuda::std::tuple<_Iterators...>& __iters2,
::cuda::std::index_sequence<_Indices...>) const
noexcept(__zip_iter_constraints<_Iterators...>::__all_noexcept_swappable)
{
(::cuda::std::ranges::__iter_swap_cpo{}(
::cuda::std::get<_Indices>(__iters1), ::cuda::std::get<_Indices>(__iters2)),
...);
}
};
//! @brief Applies `iter_swap` to two @c zip_iterator by applying it to all stored iterators
template <class _Constraints = __zip_iter_constraints<_Iterators...>>
_CCCL_API friend constexpr auto
iter_swap(const zip_iterator& __lhs, const zip_iterator& __rhs) noexcept(_Constraints::__all_noexcept_swappable)
_CCCL_TRAILING_REQUIRES(void)(_Constraints::__all_indirectly_swappable)
{
return __zip_apply(__zip_op_iter_swap{}, __lhs.__current_, __rhs.__current_);
}
[[nodiscard]] _CCCL_API constexpr ::cuda::std::tuple<_Iterators...>& __iterators() noexcept
{
return __current_;
}
[[nodiscard]] _CCCL_API constexpr const ::cuda::std::tuple<_Iterators...>& __iterators() const noexcept
{
return __current_;
}
};
#ifndef _CCCL_DOXYGEN_INVOKED
template <class... _Iterators>
_CCCL_DEDUCTION_GUIDE_ATTRIBUTES zip_iterator(::cuda::std::tuple<_Iterators...>) -> zip_iterator<_Iterators...>;
template <class... _Iterators>
_CCCL_DEDUCTION_GUIDE_ATTRIBUTES zip_iterator(_Iterators...) -> zip_iterator<_Iterators...>;
#endif // _CCCL_DOXYGEN_INVOKED
//! @brief Creates a @c zip_iterator from a tuple of iterators.
//! @param __t The tuple of iterators to wrap
//! @relates zip_iterator
template <typename... Iterators>
_CCCL_API constexpr zip_iterator<Iterators...> make_zip_iterator(::cuda::std::tuple<Iterators...> __t)
{
return zip_iterator<Iterators...>{::cuda::std::move(__t)};
}
//! @brief Creates a @c zip_iterator from a variadic number of iterators.
//! @param __iters The iterators to wrap
//! @relates zip_iterator
template <typename... Iterators>
_CCCL_API constexpr zip_iterator<Iterators...> make_zip_iterator(Iterators... __iters)
{
return zip_iterator<Iterators...>{::cuda::std::move(__iters)...};
}
//! @}
_CCCL_END_NAMESPACE_CUDA
// GCC and MSVC2019 have issues determining __is_fancy_pointer in C++17 because they fail to instantiate pointer_traits
#if (_CCCL_COMPILER(GCC) || _CCCL_COMPILER(MSVC)) && _CCCL_STD_VER <= 2017
_CCCL_BEGIN_NAMESPACE_CUDA_STD
template <class... _Iterators>
inline constexpr bool __is_fancy_pointer<::cuda::zip_iterator<_Iterators...>> = false;
_CCCL_END_NAMESPACE_CUDA_STD
#endif // _CCCL_COMPILER(MSVC) && _CCCL_STD_VER <= 2017
#ifndef _CCCL_DOXYGEN_INVOKED
# if _CCCL_HAS_HOST_STD_LIB()
_CCCL_BEGIN_NAMESPACE_STD
//! zip_iterator is a C++20 iterator, so it does not play well with legacy STL features like std::distance
//! To work around that specialize those functions for zip_iterator
template <class _Diff, class... _Iterators>
_CCCL_HOST_API constexpr void advance(::cuda::zip_iterator<_Iterators...>& __iter, _Diff __diff)
{
::cuda::std::advance(__iter, ::cuda::std::move(__diff));
}
template <class... _Iterators>
[[nodiscard]] _CCCL_HOST_API constexpr ::cuda::std::common_type_t<::cuda::std::iter_difference_t<_Iterators>...>
distance(::cuda::zip_iterator<_Iterators...> __first, ::cuda::zip_iterator<_Iterators...> __last)
{
return ::cuda::std::distance(::cuda::std::move(__first), ::cuda::std::move(__last));
}
template <class... _Iterators>
[[nodiscard]] _CCCL_HOST_API constexpr ::cuda::zip_iterator<_Iterators...>
next(::cuda::zip_iterator<_Iterators...> __iter,
::cuda::std::common_type_t<::cuda::std::iter_difference_t<_Iterators>...> __n = 1)
{
_CCCL_ASSERT(__n >= 0 || ::cuda::__zip_iter_constraints<_Iterators...>::__all_bidirectional,
"Attempt to std::next(it, n) with negative n on a non-bidirectional iterator");
::cuda::std::advance(__iter, __n);
return __iter;
}
template <class... _Iterators>
[[nodiscard]] _CCCL_HOST_API constexpr ::cuda::zip_iterator<_Iterators...>
prev(::cuda::zip_iterator<_Iterators...> __iter,
::cuda::std::common_type_t<::cuda::std::iter_difference_t<_Iterators>...> __n = 1)
{
_CCCL_ASSERT(__n <= 0 || ::cuda::__zip_iter_constraints<_Iterators...>::__all_bidirectional,
"Attempt to std::prev(it, +n) on a non-bidi iterator");
::cuda::std::advance(__iter, -__n);
return __iter;
}
_CCCL_END_NAMESPACE_STD
# endif // _CCCL_HAS_HOST_STD_LIB()
#endif // _CCCL_DOXYGEN_INVOKED
#include <cuda/std/__cccl/epilogue.h>
#endif // _CUDA___ITERATOR_ZIP_ITERATOR_H

View File

@@ -0,0 +1,594 @@
// -*- 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
//
//===----------------------------------------------------------------------===//
#ifndef _CUDA___ITERATOR_ZIP_TRANSFORM_ITERATOR_H
#define _CUDA___ITERATOR_ZIP_TRANSFORM_ITERATOR_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/__fwd/iterator.h>
#include <cuda/std/__algorithm/ranges_min_element.h>
#if _LIBCUDACXX_HAS_SPACESHIP_OPERATOR()
# include <cuda/std/__compare/three_way_comparable.h>
#endif // _LIBCUDACXX_HAS_SPACESHIP_OPERATOR()
#include <cuda/__iterator/zip_common.h>
#include <cuda/std/__concepts/constructible.h>
#include <cuda/std/__concepts/convertible_to.h>
#include <cuda/std/__concepts/equality_comparable.h>
#include <cuda/std/__functional/invoke.h>
#include <cuda/std/__functional/operations.h>
#include <cuda/std/__iterator/advance.h>
#include <cuda/std/__iterator/concepts.h>
#include <cuda/std/__iterator/distance.h>
#include <cuda/std/__iterator/incrementable_traits.h>
#include <cuda/std/__iterator/iterator_traits.h>
#include <cuda/std/__ranges/compressed_movable_box.h>
#include <cuda/std/__ranges/concepts.h>
#include <cuda/std/__ranges/movable_box.h>
#include <cuda/std/__type_traits/common_type.h>
#include <cuda/std/__type_traits/make_unsigned.h>
#include <cuda/std/__type_traits/remove_cvref.h>
#include <cuda/std/__utility/forward.h>
#include <cuda/std/__utility/integer_sequence.h>
#include <cuda/std/__utility/move.h>
#include <cuda/std/tuple>
#include <cuda/std/__cccl/prologue.h>
_CCCL_BEGIN_NAMESPACE_CUDA
//! @addtogroup iterators
//! @{
template <class _Fn, class... _Iterators>
[[nodiscard]] _CCCL_API _CCCL_CONSTEVAL auto __get_zip_transform_iterator_category()
{
using _Constraints = __zip_iter_constraints<_Iterators...>;
// NOLINTBEGIN(bugprone-branch-clone)
if constexpr (!::cuda::std::is_reference_v<
::cuda::std::invoke_result_t<_Fn&, ::cuda::std::iter_reference_t<_Iterators>...>>)
{
return ::cuda::std::input_iterator_tag{};
}
else if constexpr (_Constraints::__all_random_access)
{
return ::cuda::std::random_access_iterator_tag{};
}
else if constexpr (_Constraints::__all_bidirectional)
{
return ::cuda::std::bidirectional_iterator_tag{};
}
else if constexpr (_Constraints::__all_forward)
{
return ::cuda::std::forward_iterator_tag{};
}
else
{
return ::cuda::std::input_iterator_tag{};
}
// NOLINTEND(bugprone-branch-clone)
}
//! @brief @c zip_transform_iterator is an iterator which represents the result of a transformation of a set of
//! sequences with a given function. This iterator is useful for creating a range filled with the result of applying an
//! operation to another range without either explicitly storing it in memory, or explicitly executing the
//! transformation. Using @c zip_transform_iterator facilitates kernel fusion by deferring the execution of a
//! transformation until the value is needed while saving both memory capacity and bandwidth.
//!
//! @c zip_transform_iterator is morally equivalent to a combination of transform_iterator and zip_iterator
//!
//! @code{.cpp}
//! template <class Fn, class... Iterators>
//! using zip_transform_iterator = cuda::transform_iterator<cuda::zip_iterator<Iterators...>, cuda::zip_function<Fn>>;
//! @endcode
//!
//! @c zip_transform_iterator has the additional benefit that it does not require an artificial @c zip_function to work
//! and more importantly does not need to materialize the result of dereferencing the stored iterators when passing them
//! to the stored function.
//!
//! The following code snippet demonstrates how to create a @c zip_transform_iterator which represents the result of
//! "zipping" multiple ranges together.
//!
//! @code
//! #include <cuda/iterator>
//! #include <thrust/device_vector.h>
//!
//! struct SumArgs {
//! __host__ __device__ float operator()(float a, float b, float c) const noexcept {
//! return a + b + c;
//! }
//! };
//!
//! thrust::device_vector<float> A{0.f, 1.f, 2.f};
//! thrust::device_vector<float> B{1.f, 2.f, 3.f};
//! thrust::device_vector<float> C{2.f, 3.f, 4.f};
//!
//! cuda::zip_transform_iterator iter{SumArgs{}, A.begin(), B.begin(), C.begin()};
//!
//! *iter; // returns (3.f)
//! iter[0]; // returns (3.f)
//! iter[1]; // returns (6.f)
//! iter[2]; // returns (9.f)
//! // iter[3] is an out-of-bounds error
//! @endcode
//!
//! This example shows how to use @c zip_transform_iterator to copy multiple ranges with a single call to @c
//! thrust::copy.
//!
//! @code
//! #include <cuda/iterator>
//! #include <thrust/device_vector.h>
//!
//! int main()
//! {
//! struct SumArgs {
//! __host__ __device__ float operator()(float a, float b, float c) const noexcept {
//! return a + b + c;
//! }
//! };
//!
//! thrust::device_vector<float> A{0.f, 1.f, 2.f};
//! thrust::device_vector<float> B{1.f, 2.f, 3.f};
//! thrust::device_vector<float> C{2.f, 3.f, 4.f};
//! thrust::device_vector<float> out(3);
//!
//! cuda::zip_transform_iterator iter{SumArgs{}, A.begin(), B.begin(), C.begin()}
//! thrust::copy(iter, iter + 3, out.begin());
//!
//! // out is now [3.0f, 6.0f, 9.0f]
//!
//! return 0;
//! }
//! @endcode
template <class _Fn, class... _Iterators>
class zip_transform_iterator
{
private:
// Not a base because then the friend operators would be ambiguous
::cuda::std::__compressed_movable_box<::cuda::std::tuple<_Iterators...>, _Fn> __store_;
[[nodiscard]] _CCCL_API constexpr ::cuda::std::tuple<_Iterators...>& __iters() noexcept
{
return __store_.template __get<0>();
}
[[nodiscard]] _CCCL_API constexpr const ::cuda::std::tuple<_Iterators...>& __iters() const noexcept
{
return __store_.template __get<0>();
}
[[nodiscard]] _CCCL_API constexpr _Fn& __func() noexcept
{
return __store_.template __get<1>();
}
[[nodiscard]] _CCCL_API constexpr const _Fn& __func() const noexcept
{
return __store_.template __get<1>();
}
template <class, class...>
friend class zip_transform_iterator;
template <class _Op>
_CCCL_API static constexpr auto
__zip_apply(const _Op& __op,
const ::cuda::std::tuple<_Iterators...>& __tuple1,
const ::cuda::std::tuple<_Iterators...>& __tuple2) //
noexcept(noexcept(__op(__tuple1, __tuple2, ::cuda::std::make_index_sequence<sizeof...(_Iterators)>())))
{
return __op(__tuple1, __tuple2, ::cuda::std::make_index_sequence<sizeof...(_Iterators)>());
}
public:
//! @brief Default-constructs a @c zip_transform_iterator by value-initializing the functor and all stored iterators
_CCCL_EXEC_CHECK_DISABLE
_CCCL_TEMPLATE(class _Fn2 = _Fn)
_CCCL_REQUIRES(
::cuda::std::default_initializable<_Fn2>&& __zip_iter_constraints<_Iterators...>::__all_default_initializable)
_CCCL_API constexpr zip_transform_iterator() noexcept(
::cuda::std::is_nothrow_default_constructible_v<_Fn2>
&& __zip_iter_constraints<_Iterators...>::__all_nothrow_default_constructible)
: __store_()
{}
//! @brief Constructs a @c zip_transform_iterator from a tuple of iterators
//! @param __fun The functor used to transform dereferenced elements.
//! @param __iters A tuple or pair of iterators
_CCCL_API constexpr explicit zip_transform_iterator(_Fn __fun, ::cuda::std::tuple<_Iterators...> __iters)
: __store_(::cuda::std::move(__iters), ::cuda::std::move(__fun))
{}
//! @brief Constructs a @c zip_transform_iterator from variadic set of iterators
//! @param __fun The functor used to transform dereferenced elements.
//! @param __iters The input iterators
_CCCL_API constexpr explicit zip_transform_iterator(_Fn __fun, _Iterators... __iters)
: __store_(::cuda::std::tuple<_Iterators...>{::cuda::std::move(__iters)...}, ::cuda::std::move(__fun))
{}
using iterator_concept = decltype(::cuda::__get_zip_iterator_concept<_Iterators...>());
using iterator_category = decltype(::cuda::__get_zip_transform_iterator_category<_Fn, _Iterators...>());
using difference_type = ::cuda::std::common_type_t<::cuda::std::iter_difference_t<_Iterators>...>;
using value_type =
::cuda::std::remove_cvref_t<::cuda::std::invoke_result_t<_Fn&, ::cuda::std::iter_reference_t<_Iterators>...>>;
// Those are technically not to spec, but pre-ranges iterator_traits do not work properly with iterators that do not
// define all 5 aliases, see https://en.cppreference.com/w/cpp/iterator/iterator_traits.html
using reference = ::cuda::std::invoke_result_t<_Fn&, ::cuda::std::iter_reference_t<_Iterators>...>;
using pointer = void;
// Internal helper functions to extract internals for device dispatch, must be a tuple for cub_transform_many
[[nodiscard]] _CCCL_API constexpr ::cuda::std::tuple<_Iterators...>
__base() && noexcept(::cuda::std::is_nothrow_move_constructible_v<::cuda::std::tuple<_Iterators...>>)
{
return ::cuda::std::move(__iters());
}
[[nodiscard]] _CCCL_API constexpr _Fn __pred() && noexcept(::cuda::std::is_nothrow_move_constructible_v<_Fn>)
{
return ::cuda::std::move(__func());
}
struct __zip_transform_op_star
{
_Fn& __func_;
_CCCL_EXEC_CHECK_DISABLE
[[nodiscard]] _CCCL_API constexpr reference operator()(const _Iterators&... __iters) const
noexcept(::cuda::std::is_nothrow_invocable_v<_Fn&, ::cuda::std::iter_reference_t<const _Iterators>...>)
{
return ::cuda::std::invoke(const_cast<_Fn&>(__func_), *__iters...);
}
};
//! @brief Invokes the stored function with the result of dereferencing the stored iterators
[[nodiscard]] _CCCL_API constexpr reference operator*() const
noexcept(::cuda::std::is_nothrow_invocable_v<_Fn&, ::cuda::std::iter_reference_t<const _Iterators>...>)
{
return ::cuda::std::apply(__zip_transform_op_star{const_cast<_Fn&>(__func())}, __iters());
}
struct __zip_transform_op_subscript
{
difference_type __n_;
_Fn& __func_;
_CCCL_EXEC_CHECK_DISABLE
[[nodiscard]] _CCCL_API constexpr reference operator()(const _Iterators&... __iters) const noexcept(noexcept(
::cuda::std::invoke(const_cast<_Fn&>(__func_), __iters[::cuda::std::iter_difference_t<_Iterators>(__n_)]...)))
{
return ::cuda::std::invoke(
const_cast<_Fn&>(__func_), __iters[::cuda::std::iter_difference_t<_Iterators>(__n_)]...);
}
};
//! @brief Invokes the stored function with the result of dereferencing the stored iterators advanced by an offset
//! @param __n The additional offset
_CCCL_TEMPLATE(class _Constraints = __zip_iter_constraints<_Iterators...>)
_CCCL_REQUIRES(_Constraints::__all_random_access)
_CCCL_API constexpr reference operator[](difference_type __n) const
noexcept(noexcept(::cuda::std::apply(__zip_transform_op_subscript{__n, ::cuda::std::declval<_Fn&>()},
::cuda::std::declval<const ::cuda::std::tuple<_Iterators...>&>())))
{
return ::cuda::std::apply(__zip_transform_op_subscript{__n, const_cast<_Fn&>(__func())}, __iters());
}
//! @brief Increments all stored iterators
_CCCL_API constexpr zip_transform_iterator& operator++() noexcept(
noexcept(::cuda::std::apply(__zip_op_increment{}, ::cuda::std::declval<::cuda::std::tuple<_Iterators...>&>())))
{
::cuda::std::apply(__zip_op_increment{}, __iters());
return *this;
}
//! @brief Increments all stored iterators
//! @returns A copy of the original @c zip_transform_iterator if possible
_CCCL_API constexpr auto operator++(int)
{
if constexpr (__zip_iter_constraints<_Iterators...>::__all_forward)
{
auto __tmp = *this;
++*this;
return __tmp;
}
else
{
++*this;
}
}
//! @brief Decrements all stored iterators
_CCCL_TEMPLATE(class _Constraints = __zip_iter_constraints<_Iterators...>)
_CCCL_REQUIRES(_Constraints::__all_bidirectional)
_CCCL_API constexpr zip_transform_iterator& operator--() noexcept(
noexcept(::cuda::std::apply(__zip_op_decrement{}, ::cuda::std::declval<::cuda::std::tuple<_Iterators...>&>())))
{
::cuda::std::apply(__zip_op_decrement{}, __iters());
return *this;
}
//! @brief Decrements all stored iterators
_CCCL_TEMPLATE(class _Constraints = __zip_iter_constraints<_Iterators...>)
_CCCL_REQUIRES(_Constraints::__all_bidirectional)
_CCCL_API constexpr zip_transform_iterator operator--(int)
{
auto __tmp = *this;
--*this;
return __tmp;
}
struct __zip_op_pe
{
difference_type __n;
_CCCL_EXEC_CHECK_DISABLE
_CCCL_API constexpr void operator()(_Iterators&... __iters) const
noexcept(noexcept(((void) (__iters += ::cuda::std::iter_difference_t<_Iterators>(__n)), ...)))
{
((void) (__iters += ::cuda::std::iter_difference_t<_Iterators>(__n)), ...);
}
};
//! @brief Increments all stored iterators by a given number of elements
//! @param __n The number of elements to increment
_CCCL_TEMPLATE(class _Constraints = __zip_iter_constraints<_Iterators...>)
_CCCL_REQUIRES(_Constraints::__all_random_access)
_CCCL_API constexpr zip_transform_iterator& operator+=(difference_type __n) noexcept(
noexcept(::cuda::std::apply(__zip_op_pe{__n}, ::cuda::std::declval<::cuda::std::tuple<_Iterators...>&>())))
{
::cuda::std::apply(__zip_op_pe{__n}, __iters());
return *this;
}
struct __zip_op_me
{
difference_type __n;
_CCCL_EXEC_CHECK_DISABLE
_CCCL_API constexpr void operator()(_Iterators&... __iters) const
noexcept(noexcept(((void) (__iters -= ::cuda::std::iter_difference_t<_Iterators>(__n)), ...)))
{
((void) (__iters -= ::cuda::std::iter_difference_t<_Iterators>(__n)), ...);
}
};
//! @brief Decrements all stored iterators by a given number of elements
//! @param __n The number of elements to decrement
_CCCL_TEMPLATE(class _Constraints = __zip_iter_constraints<_Iterators...>)
_CCCL_REQUIRES(_Constraints::__all_random_access)
_CCCL_API constexpr zip_transform_iterator& operator-=(difference_type __n) noexcept(
noexcept(::cuda::std::apply(__zip_op_me{__n}, ::cuda::std::declval<::cuda::std::tuple<_Iterators...>&>())))
{
::cuda::std::apply(__zip_op_me{__n}, __iters());
return *this;
}
//! @brief Returns a copy of a @c zip_transform_iterator incremented by a given number of elements
//! @param __iter The @c zip_transform_iterator to increment
//! @param __n The number of elements to increment
template <class _Constraints = __zip_iter_constraints<_Iterators...>>
_CCCL_API friend constexpr auto operator+(const zip_transform_iterator& __iter, difference_type __n)
_CCCL_TRAILING_REQUIRES(zip_transform_iterator)(_Constraints::__all_random_access)
{
auto __rhs = __iter;
__rhs += __n;
return __rhs;
}
//! @brief Returns a copy of a @c zip_transform_iterator incremented by a given number of elements
//! @param __n The number of elements to increment
//! @param __iter The @c zip_transform_iterator to increment
template <class _Constraints = __zip_iter_constraints<_Iterators...>>
_CCCL_API friend constexpr auto operator+(difference_type __n, const zip_transform_iterator& __iter)
_CCCL_TRAILING_REQUIRES(zip_transform_iterator)(_Constraints::__all_random_access)
{
return __iter + __n;
}
//! @brief Returns a copy of a @c zip_transform_iterator decremented by a given number of elements
//! @param __n The number of elements to decrement
//! @param __iter The @c zip_transform_iterator to decrement
template <class _Constraints = __zip_iter_constraints<_Iterators...>>
_CCCL_API friend constexpr auto operator-(const zip_transform_iterator& __iter, difference_type __n)
_CCCL_TRAILING_REQUIRES(zip_transform_iterator)(_Constraints::__all_random_access)
{
auto __rhs = __iter;
__rhs -= __n;
return __rhs;
}
//! @brief Returns the distance between two @c zip_transform_iterators
//! @returns The minimal distance between any of the stored iterators
template <class _Constraints = __zip_iter_constraints<_Iterators...>>
_CCCL_API friend constexpr auto operator-(const zip_transform_iterator& __n, const zip_transform_iterator& __y)
_CCCL_TRAILING_REQUIRES(difference_type)(_Constraints::__all_sized_sentinel)
{
return __zip_apply(__zip_op_minus<difference_type>{}, __n.__iters(), __y.__iters());
}
//! @brief Compares two @c zip_transform_iterator for equality by comparing the tuple of stored iterators
template <class _Constraints = __zip_iter_constraints<_Iterators...>>
_CCCL_API friend constexpr auto operator==(const zip_transform_iterator& __n, const zip_transform_iterator& __y)
_CCCL_TRAILING_REQUIRES(bool)(_Constraints::__all_equality_comparable)
{
if constexpr (_Constraints::__all_bidirectional)
{
return __n.__iters() == __y.__iters();
}
else
{
return __zip_apply(__zip_op_eq{}, __n.__iters(), __y.__iters());
}
}
#if _CCCL_STD_VER <= 2017
//! @brief Compares two @c zip_transform_iterator for inequality by comparing the tuple of stored iterators
template <class _Constraints = __zip_iter_constraints<_Iterators...>>
_CCCL_API friend constexpr auto operator!=(const zip_transform_iterator& __n, const zip_transform_iterator& __y)
_CCCL_TRAILING_REQUIRES(bool)(_Constraints::__all_equality_comparable)
{
if constexpr (_Constraints::__all_bidirectional)
{
return __n.__iters() != __y.__iters();
}
else
{
return !__zip_apply(__zip_op_eq{}, __n.__iters(), __y.__iters());
}
}
#endif // _CCCL_STD_VER <= 2017
#if _LIBCUDACXX_HAS_SPACESHIP_OPERATOR()
//! @brief Three-way compares two @c zip_transform_iterator by comparing the tuple of stored iterators
template <class _Constraints = __zip_iter_constraints<_Iterators...>>
_CCCL_API friend constexpr auto operator<=>(const zip_transform_iterator& __n, const zip_transform_iterator& __y)
_CCCL_TRAILING_REQUIRES(bool)(_Constraints::__all_random_access&& _Constraints::__all_three_way_comparable)
{
return __n.__iters() <=> __y.__iters();
}
#else // ^^^ _LIBCUDACXX_HAS_SPACESHIP_OPERATOR() ^^^ / vvv !_LIBCUDACXX_HAS_SPACESHIP_OPERATOR() vvv
//! @brief Compares two @c zip_transform_iterator for less than by comparing the tuple of stored iterators
template <class _Constraints = __zip_iter_constraints<_Iterators...>>
_CCCL_API friend constexpr auto operator<(const zip_transform_iterator& __n, const zip_transform_iterator& __y)
_CCCL_TRAILING_REQUIRES(bool)(_Constraints::__all_random_access)
{
return __n.__iters() < __y.__iters();
}
//! @brief Compares two @c zip_transform_iterator for greater than by comparing the tuple of stored iterators
template <class _Constraints = __zip_iter_constraints<_Iterators...>>
_CCCL_API friend constexpr auto operator>(const zip_transform_iterator& __n, const zip_transform_iterator& __y)
_CCCL_TRAILING_REQUIRES(bool)(_Constraints::__all_random_access)
{
return __y < __n;
}
//! @brief Compares two @c zip_transform_iterator for less equal by comparing the tuple of stored iterators
template <class _Constraints = __zip_iter_constraints<_Iterators...>>
_CCCL_API friend constexpr auto operator<=(const zip_transform_iterator& __n, const zip_transform_iterator& __y)
_CCCL_TRAILING_REQUIRES(bool)(_Constraints::__all_random_access)
{
return !(__y < __n);
}
//! @brief Compares two @c zip_transform_iterator for greater equal by comparing the tuple of stored iterators
template <class _Constraints = __zip_iter_constraints<_Iterators...>>
_CCCL_API friend constexpr auto operator>=(const zip_transform_iterator& __n, const zip_transform_iterator& __y)
_CCCL_TRAILING_REQUIRES(bool)(_Constraints::__all_random_access)
{
return !(__n < __y);
}
#endif // !_LIBCUDACXX_HAS_SPACESHIP_OPERATOR()
};
#ifndef _CCCL_DOXYGEN_INVOKED
template <class _Fn, class... _Iterators>
_CCCL_DEDUCTION_GUIDE_ATTRIBUTES zip_transform_iterator(_Fn, ::cuda::std::tuple<_Iterators...>)
-> zip_transform_iterator<_Fn, _Iterators...>;
template <class _Fn, class... _Iterators>
_CCCL_DEDUCTION_GUIDE_ATTRIBUTES zip_transform_iterator(_Fn, _Iterators...)
-> zip_transform_iterator<_Fn, _Iterators...>;
#endif // _CCCL_DOXYGEN_INVOKED
//! @brief Creates a @c zip_transform_iterator from a tuple of iterators.
//! @param __fun The functor used to transform dereferenced elements.
//! @param __t The tuple of iterators to wrap
//! @relates zip_transform_iterator
template <class _Fn, class... _Iterators>
[[nodiscard]] _CCCL_API constexpr auto
make_zip_transform_iterator(_Fn __fun, ::cuda::std::tuple<_Iterators...> __t) noexcept(
::cuda::std::is_nothrow_move_constructible_v<_Fn>
&& __zip_iter_constraints<_Iterators...>::__all_nothrow_move_constructible)
{
return zip_transform_iterator<_Fn, _Iterators...>{::cuda::std::move(__fun), ::cuda::std::move(__t)};
}
//! @brief Creates a @c zip_transform_iterator from a variadic number of iterators.
//! @param __fun The functor used to transform dereferenced elements.
//! @param __iters The iterators to wrap
//! @relates zip_transform_iterator
template <class _Fn, class... _Iterators>
[[nodiscard]] _CCCL_API constexpr auto make_zip_transform_iterator(_Fn __fun, _Iterators... __iters) noexcept(
::cuda::std::is_nothrow_move_constructible_v<_Fn>
&& __zip_iter_constraints<_Iterators...>::__all_nothrow_move_constructible)
{
return zip_transform_iterator<_Fn, _Iterators...>{::cuda::std::move(__fun), ::cuda::std::move(__iters)...};
}
//! @}
_CCCL_END_NAMESPACE_CUDA
// GCC and MSVC2019 have issues determining __is_fancy_pointer in C++17 because they fail to instantiate pointer_traits
#if (_CCCL_COMPILER(GCC) || _CCCL_COMPILER(MSVC)) && _CCCL_STD_VER <= 2017
_CCCL_BEGIN_NAMESPACE_CUDA_STD
template <class _Fn, class... _Iterators>
inline constexpr bool __is_fancy_pointer<::cuda::zip_transform_iterator<_Fn, _Iterators...>> = false;
_CCCL_END_NAMESPACE_CUDA_STD
#endif // (_CCCL_COMPILER(GCC) || _CCCL_COMPILER(MSVC)) && _CCCL_STD_VER <= 2017
#ifndef _CCCL_DOXYGEN_INVOKED
# if _CCCL_HAS_HOST_STD_LIB()
_CCCL_BEGIN_NAMESPACE_STD
//! zip_transform_iterator is a C++20 iterator, so it does not play well with legacy STL features like std::distance
//! To work around that specialize those functions for zip_transform_iterator
template <class _Diff, class _Fn, class... _Iterators>
_CCCL_HOST_API constexpr void advance(::cuda::zip_transform_iterator<_Fn, _Iterators...>& __iter, _Diff __diff)
{
::cuda::std::advance(__iter, ::cuda::std::move(__diff));
}
template <class _Fn, class... _Iterators>
[[nodiscard]] _CCCL_HOST_API constexpr ::cuda::std::common_type_t<::cuda::std::iter_difference_t<_Iterators>...>
distance(::cuda::zip_transform_iterator<_Fn, _Iterators...> __first,
::cuda::zip_transform_iterator<_Fn, _Iterators...> __last)
{
return ::cuda::std::distance(::cuda::std::move(__first), ::cuda::std::move(__last));
}
template <class _Fn, class... _Iterators>
[[nodiscard]] _CCCL_HOST_API constexpr ::cuda::zip_transform_iterator<_Fn, _Iterators...>
next(::cuda::zip_transform_iterator<_Fn, _Iterators...> __iter,
::cuda::std::common_type_t<::cuda::std::iter_difference_t<_Iterators>...> __n = 1)
{
_CCCL_ASSERT(__n >= 0 || ::cuda::__zip_iter_constraints<_Iterators...>::__all_bidirectional,
"Attempt to std::next(it, n) with negative n on a non-bidirectional iterator");
::cuda::std::advance(__iter, __n);
return __iter;
}
template <class _Fn, class... _Iterators>
[[nodiscard]] _CCCL_HOST_API constexpr ::cuda::zip_transform_iterator<_Fn, _Iterators...>
prev(::cuda::zip_transform_iterator<_Fn, _Iterators...> __iter,
::cuda::std::common_type_t<::cuda::std::iter_difference_t<_Iterators>...> __n = 1)
{
_CCCL_ASSERT(__n <= 0 || ::cuda::__zip_iter_constraints<_Iterators...>::__all_bidirectional,
"Attempt to std::prev(it, +n) on a non-bidi iterator");
::cuda::std::advance(__iter, -__n);
return __iter;
}
_CCCL_END_NAMESPACE_STD
# endif // _CCCL_HAS_HOST_STD_LIB()
#endif // _CCCL_DOXYGEN_INVOKED
#include <cuda/std/__cccl/epilogue.h>
#endif // _CUDA___ITERATOR_ZIP_TRANSFORM_ITERATOR_H