thrust/iterator/counting_iterator.h
File members: thrust/iterator/counting_iterator.h
/*
* Copyright 2008-2013 NVIDIA Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Copyright David Abrahams 2003.
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying NOTICE file for the complete license)
*
* For more information, see http://www.boost.org
*/
#pragma once
#include <thrust/detail/config.h>
#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 <thrust/detail/type_traits.h>
#include <thrust/iterator/counting_iterator.h>
#include <thrust/iterator/iterator_adaptor.h>
#include <thrust/iterator/iterator_traits.h>
#include <thrust/iterator/strided_iterator.h>
#include <cuda/std/cstddef>
#include <cuda/std/type_traits>
#include <cuda/type_traits>
THRUST_NAMESPACE_BEGIN
template <typename Incrementable, typename System, typename Traversal, typename Difference, typename StrideHolder>
class counting_iterator;
namespace detail
{
template <typename Number>
using counting_iterator_difference_type =
::cuda::std::_If<::cuda::std::is_integral_v<Number> && sizeof(Number) < sizeof(int), int, ::cuda::std::ptrdiff_t>;
template <typename Incrementable, typename System, typename Traversal, typename Difference, typename StrideHolder>
struct make_counting_iterator_base
{
using system =
typename eval_if<::cuda::std::is_same<System, use_default>::value, identity_<any_system_tag>, identity_<System>>::type;
using traversal = replace_if_use_default<Traversal, ::cuda::std::type_identity<random_access_traversal_tag>>;
using difference =
replace_if_use_default<Difference, ::cuda::std::type_identity<counting_iterator_difference_type<Incrementable>>>;
// our implementation departs from Boost's in that counting_iterator::dereference
// returns a copy of its counter, rather than a reference to it. returning a reference
// to the internal state of an iterator causes subtle bugs (consider the temporary
// iterator created in the expression *(iter + i)) and has no compelling use case
using type =
iterator_adaptor<counting_iterator<Incrementable, System, Traversal, Difference, StrideHolder>,
Incrementable,
Incrementable,
system,
traversal,
Incrementable,
difference>;
};
using unit_stride = compile_time_value<1>;
} // namespace detail
template <typename Incrementable,
typename System = use_default,
typename Traversal = use_default,
typename Difference = use_default,
typename StrideHolder = detail::unit_stride>
class _CCCL_DECLSPEC_EMPTY_BASES counting_iterator
: public detail::make_counting_iterator_base<Incrementable, System, Traversal, Difference, StrideHolder>::type
, StrideHolder
{
using super_t =
typename detail::make_counting_iterator_base<Incrementable, System, Traversal, Difference, StrideHolder>::type;
friend class iterator_core_access;
public:
using reference = typename super_t::reference;
using difference_type = typename super_t::difference_type;
_CCCL_HOST_DEVICE counting_iterator()
: super_t(Incrementable{})
{}
template <class OtherSystem,
detail::enable_if_convertible_t<
iterator_system_t<counting_iterator<Incrementable, OtherSystem, Traversal, Difference, StrideHolder>>,
iterator_system_t<super_t>,
int> = 0>
_CCCL_HOST_DEVICE
counting_iterator(counting_iterator<Incrementable, OtherSystem, Traversal, Difference, StrideHolder> const& rhs)
: super_t(rhs.base())
{}
_CCCL_HOST_DEVICE explicit counting_iterator(Incrementable x)
: super_t(x)
{}
_CCCL_HOST_DEVICE explicit counting_iterator(Incrementable x, StrideHolder stride)
: super_t(x)
, StrideHolder(stride)
{}
private:
template <typename S = StrideHolder>
_CCCL_HOST_DEVICE auto stride() const
{
return static_cast<const S&>(*this).value;
}
_CCCL_EXEC_CHECK_DISABLE
_CCCL_HOST_DEVICE void advance(difference_type n)
{
if constexpr (::cuda::std::is_same_v<StrideHolder, detail::unit_stride>)
{
this->base_reference() = static_cast<Incrementable>(this->base_reference() + n);
}
else
{
this->base_reference() += n * stride();
}
}
_CCCL_EXEC_CHECK_DISABLE
_CCCL_HOST_DEVICE void increment()
{
if constexpr (::cuda::std::is_same_v<StrideHolder, detail::unit_stride>)
{
++this->base_reference();
}
else
{
this->base_reference() += stride();
}
}
_CCCL_EXEC_CHECK_DISABLE
_CCCL_HOST_DEVICE void decrement()
{
if constexpr (::cuda::std::is_same_v<StrideHolder, detail::unit_stride>)
{
--this->base_reference();
}
else
{
this->base_reference() -= stride();
}
}
_CCCL_HOST_DEVICE reference dereference() const
{
return this->base_reference();
}
// note that we implement equal specially for floating point counting_iterator
template <typename OtherSystem, typename OtherTraversal, typename OtherDifference, typename OtherStrideHolder>
_CCCL_HOST_DEVICE bool equal(
counting_iterator<Incrementable, OtherSystem, OtherTraversal, OtherDifference, OtherStrideHolder> const& y) const
{
if constexpr (::cuda::is_floating_point_v<Incrementable>)
{
return distance_to(y) == 0;
}
else
{
return this->base() == y.base();
}
}
template <typename OtherSystem, typename OtherTraversal, typename OtherDifference>
_CCCL_HOST_DEVICE difference_type distance_to(
counting_iterator<Incrementable, OtherSystem, OtherTraversal, OtherDifference, StrideHolder> const& y) const
{
if constexpr (::cuda::std::is_integral<Incrementable>::value)
{
return static_cast<difference_type>(y.base()) - static_cast<difference_type>(this->base());
}
else
{
return y.base() - this->base();
}
}
};
template <typename Incrementable>
inline _CCCL_HOST_DEVICE counting_iterator<Incrementable> make_counting_iterator(Incrementable x)
{
return counting_iterator<Incrementable>(x);
}
// FIXME(bgruber): Sphinx fails to document the fancyiterators group if make_counting_iterator has overloads, so we
// exclude them for now
#ifndef _CCCL_DOXYGEN_INVOKED // Do not document
template <typename Incrementable, typename Stride>
_CCCL_HOST_DEVICE auto make_counting_iterator(Incrementable x, Stride stride)
{
return counting_iterator<Incrementable, use_default, random_access_traversal_tag, use_default, runtime_value<Stride>>(
x, {stride});
}
template <auto Stride, typename Incrementable>
_CCCL_HOST_DEVICE auto make_counting_iterator(Incrementable x)
{
return counting_iterator<Incrementable,
use_default,
random_access_traversal_tag,
use_default,
compile_time_value<Stride>>(x, {});
}
#endif // _CCCL_DOXYGEN_INVOKED
THRUST_NAMESPACE_END