[INFRA] Import NVIDIA/CCCL upstream as optimization reference library
CCCL (CUDA C++ Core Libraries) provides: - CUB: device/block/warp-level GPU primitives (reduce, scan, sort, topk) - Thrust: high-level parallel algorithms (transform_reduce, sort, scan) - libcudacxx: CUDA C++ standard library (atomics, barriers, memory) - cudax: experimental features (memory resources, allocators) - Tuning policies: per-SM hardware-specific algorithm parameters Competition optimization vectors mapped to CCCL: - Output TPS (83% weight): warp_reduce, block_reduce, device_topk - Input TPS (14% weight): device_scan, block_load, prefetch - Cache TPS (3% weight): prefix caching strategy patterns - Memory (0.9 util): pooled/cached/buddy allocators Source: https://github.com/NVIDIA/cccl (shallow clone, HEAD only) License: Apache-2.0
This commit is contained in:
@@ -0,0 +1,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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
282
cccl_upstream/libcudacxx/include/cuda/__iterator/zip_common.h
Normal file
282
cccl_upstream/libcudacxx/include/cuda/__iterator/zip_common.h
Normal 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
|
||||
125
cccl_upstream/libcudacxx/include/cuda/__iterator/zip_function.h
Normal file
125
cccl_upstream/libcudacxx/include/cuda/__iterator/zip_function.h
Normal 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
|
||||
550
cccl_upstream/libcudacxx/include/cuda/__iterator/zip_iterator.h
Normal file
550
cccl_upstream/libcudacxx/include/cuda/__iterator/zip_iterator.h
Normal 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
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user