You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
344 lines
12 KiB
344 lines
12 KiB
/* |
|
* Copyright 2008-2012 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. |
|
*/ |
|
|
|
|
|
/*! \file thrust/iterator/transform_iterator.h |
|
* \brief An iterator which adapts another iterator by applying a function to the result of its dereference |
|
*/ |
|
|
|
/* |
|
* (C) Copyright David Abrahams 2002. |
|
* (C) Copyright Jeremy Siek 2002. |
|
* (C) Copyright Thomas Witt 2002. |
|
* |
|
* 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> |
|
|
|
// #include the details first |
|
#include <thrust/iterator/detail/transform_iterator.inl> |
|
#include <thrust/iterator/iterator_facade.h> |
|
#include <thrust/detail/type_traits.h> |
|
#include <thrust/detail/function.h> |
|
|
|
namespace thrust |
|
{ |
|
|
|
/*! \addtogroup iterators |
|
* \{ |
|
*/ |
|
|
|
/*! \addtogroup fancyiterator Fancy Iterators |
|
* \ingroup iterators |
|
* \{ |
|
*/ |
|
|
|
/*! \p transform_iterator is an iterator which represents a pointer into a range |
|
* of values after transformation by a 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 \p 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 \p transform_iterator |
|
* which represents the result of \c sqrtf applied to the contents of a \p device_vector. |
|
* |
|
* \code |
|
* #include <thrust/iterator/transform_iterator.h> |
|
* #include <thrust/device_vector.h> |
|
* |
|
* // note: functor inherits from unary_function |
|
* struct square_root : public thrust::unary_function<float,float> |
|
* { |
|
* __host__ __device__ |
|
* float operator()(float x) const |
|
* { |
|
* return sqrtf(x); |
|
* } |
|
* }; |
|
* |
|
* int main(void) |
|
* { |
|
* thrust::device_vector<float> v(4); |
|
* v[0] = 1.0f; |
|
* v[1] = 4.0f; |
|
* v[2] = 9.0f; |
|
* v[3] = 16.0f; |
|
* |
|
* typedef thrust::device_vector<float>::iterator FloatIterator; |
|
* |
|
* thrust::transform_iterator<square_root, FloatIterator> 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 \p transform_iterator with the |
|
* \p thrust::reduce function to compute the sum of squares of a sequence. |
|
* We will create temporary \p transform_iterators with the |
|
* \p make_transform_iterator function in order to avoid explicitly specifying their type: |
|
* |
|
* \code |
|
* #include <thrust/iterator/transform_iterator.h> |
|
* #include <thrust/device_vector.h> |
|
* #include <thrust/reduce.h> |
|
* #include <iostream> |
|
* |
|
* // note: functor inherits from unary_function |
|
* struct square : public thrust::unary_function<float,float> |
|
* { |
|
* __host__ __device__ |
|
* float operator()(float x) const |
|
* { |
|
* return x * x; |
|
* } |
|
* }; |
|
* |
|
* int main(void) |
|
* { |
|
* // initialize a device array |
|
* thrust::device_vector<float> v(4); |
|
* v[0] = 1.0f; |
|
* v[1] = 2.0f; |
|
* v[2] = 3.0f; |
|
* v[3] = 4.0f; |
|
* |
|
* float sum_of_squares = |
|
* thrust::reduce(thrust::make_transform_iterator(v.begin(), square()), |
|
* thrust::make_transform_iterator(v.end(), square())); |
|
* |
|
* std::cout << "sum of squares: " << sum_of_squares << std::endl; |
|
* return 0; |
|
* } |
|
* \endcode |
|
* |
|
* Note that in the previous two examples the transform functor (namely \c square_root |
|
* and \c square) inherits from \c thrust::unary_function. Inheriting from |
|
* \c thrust::unary_function ensures that a functor is a valid \c AdaptableUnaryFunction |
|
* and provides all the necessary \c typedef declarations. The \p transform_iterator |
|
* can also be applied to a \c UnaryFunction that does not inherit from |
|
* \c thrust::unary_function using an optional template argument. The following example |
|
* illustrates how to use the third template argument to specify the \c result_type of |
|
* the function. |
|
* |
|
* \code |
|
* #include <thrust/iterator/transform_iterator.h> |
|
* #include <thrust/device_vector.h> |
|
* |
|
* // note: functor *does not* inherit from unary_function |
|
* struct square_root |
|
* { |
|
* __host__ __device__ |
|
* float operator()(float x) const |
|
* { |
|
* return sqrtf(x); |
|
* } |
|
* }; |
|
* |
|
* int main(void) |
|
* { |
|
* thrust::device_vector<float> v(4); |
|
* v[0] = 1.0f; |
|
* v[1] = 4.0f; |
|
* v[2] = 9.0f; |
|
* v[3] = 16.0f; |
|
* |
|
* typedef thrust::device_vector<float>::iterator FloatIterator; |
|
* |
|
* // note: float result_type is specified explicitly |
|
* thrust::transform_iterator<square_root, FloatIterator, float> 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 |
|
* |
|
* \see make_transform_iterator |
|
*/ |
|
template <class AdaptableUnaryFunction, class Iterator, class Reference = use_default, class Value = use_default> |
|
class transform_iterator |
|
: public detail::transform_iterator_base<AdaptableUnaryFunction, Iterator, Reference, Value>::type |
|
{ |
|
/*! \cond |
|
*/ |
|
public: |
|
typedef typename |
|
detail::transform_iterator_base<AdaptableUnaryFunction, Iterator, Reference, Value>::type |
|
super_t; |
|
|
|
friend class thrust::iterator_core_access; |
|
/*! \endcond |
|
*/ |
|
|
|
public: |
|
/*! Null constructor does nothing. |
|
*/ |
|
__host__ __device__ |
|
transform_iterator() {} |
|
|
|
/*! This constructor takes as arguments an \c Iterator and an \c AdaptableUnaryFunction |
|
* and copies them to a new \p transform_iterator. |
|
* |
|
* \param x An \c Iterator pointing to the input to this \p transform_iterator's \c AdaptableUnaryFunction. |
|
* \param f An \c AdaptableUnaryFunction used to transform the objects pointed to by \p x. |
|
*/ |
|
__host__ __device__ |
|
transform_iterator(Iterator const& x, AdaptableUnaryFunction f) |
|
: super_t(x), m_f(f) { |
|
} |
|
|
|
/*! This explicit constructor copies the value of a given \c Iterator and creates |
|
* this \p transform_iterator's \c AdaptableUnaryFunction using its null constructor. |
|
* |
|
* \param x An \c Iterator to copy. |
|
*/ |
|
__host__ __device__ |
|
explicit transform_iterator(Iterator const& x) |
|
: super_t(x) { } |
|
|
|
/*! This copy constructor creates a new \p transform_iterator from another |
|
* \p transform_iterator. |
|
* |
|
* \param other The \p transform_iterator to copy. |
|
*/ |
|
template<typename OtherAdaptableUnaryFunction, |
|
typename OtherIterator, |
|
typename OtherReference, |
|
typename OtherValue> |
|
__host__ __device__ |
|
transform_iterator(const transform_iterator<OtherAdaptableUnaryFunction, OtherIterator, OtherReference, OtherValue> &other, |
|
typename thrust::detail::enable_if_convertible<OtherIterator, Iterator>::type* = 0, |
|
typename thrust::detail::enable_if_convertible<OtherAdaptableUnaryFunction, AdaptableUnaryFunction>::type* = 0) |
|
: super_t(other.base()), m_f(other.functor()) {} |
|
|
|
/*! Copy assignment operator copies from another \p transform_iterator. |
|
* \p other The other \p transform_iterator to copy |
|
* \return <tt>*this</tt> |
|
* |
|
* \note If the type of this \p transform_iterator's functor is not copy assignable |
|
* (for example, if it is a lambda) it is not an error to call this function. |
|
* In this case, however, the functor will not be modified. |
|
* |
|
* In any case, this \p transform_iterator's underlying iterator will be copy assigned. |
|
*/ |
|
__host__ __device__ |
|
transform_iterator &operator=(const transform_iterator &other) |
|
{ |
|
return do_assign(other, |
|
// XXX gcc 4.2.1 crashes on is_copy_assignable; just assume the functor is assignable as a WAR |
|
#if (THRUST_HOST_COMPILER == THRUST_HOST_COMPILER_GCC) && (THRUST_GCC_VERSION <= 40201) |
|
thrust::detail::true_type() |
|
#else |
|
typename thrust::detail::is_copy_assignable<AdaptableUnaryFunction>::type() |
|
#endif // THRUST_HOST_COMPILER |
|
); |
|
} |
|
|
|
/*! This method returns a copy of this \p transform_iterator's \c AdaptableUnaryFunction. |
|
* \return A copy of this \p transform_iterator's \c AdaptableUnaryFunction. |
|
*/ |
|
__host__ __device__ |
|
AdaptableUnaryFunction functor() const |
|
{ return m_f; } |
|
|
|
/*! \cond |
|
*/ |
|
private: |
|
__host__ __device__ |
|
transform_iterator &do_assign(const transform_iterator &other, thrust::detail::true_type) |
|
{ |
|
super_t::operator=(other); |
|
|
|
// do assign to m_f |
|
m_f = other.functor(); |
|
|
|
return *this; |
|
} |
|
|
|
__host__ __device__ |
|
transform_iterator &do_assign(const transform_iterator &other, thrust::detail::false_type) |
|
{ |
|
super_t::operator=(other); |
|
|
|
// don't assign to m_f |
|
|
|
return *this; |
|
} |
|
|
|
__thrust_hd_warning_disable__ |
|
__host__ __device__ |
|
typename super_t::reference dereference() const |
|
{ |
|
// XXX consider making this a member instead of a temporary created inside dereference |
|
thrust::detail::host_device_function<AdaptableUnaryFunction, typename super_t::reference> wrapped_f(m_f); |
|
|
|
return wrapped_f(*this->base()); |
|
} |
|
|
|
// tag this as mutable per Dave Abrahams in this thread: |
|
// http://lists.boost.org/Archives/boost/2004/05/65332.php |
|
mutable AdaptableUnaryFunction m_f; |
|
|
|
/*! \endcond |
|
*/ |
|
}; // end transform_iterator |
|
|
|
|
|
/*! \p make_transform_iterator creates a \p transform_iterator |
|
* from an \c Iterator and \c AdaptableUnaryFunction. |
|
* |
|
* \param it The \c Iterator pointing to the input range of the |
|
* newly created \p transform_iterator. |
|
* \param fun The \c AdaptableUnaryFunction used to transform the range pointed |
|
* to by \p it in the newly created \p transform_iterator. |
|
* \return A new \p transform_iterator which transforms the range at |
|
* \p it by \p fun. |
|
* \see transform_iterator |
|
*/ |
|
template <class AdaptableUnaryFunction, class Iterator> |
|
inline __host__ __device__ |
|
transform_iterator<AdaptableUnaryFunction, Iterator> |
|
make_transform_iterator(Iterator it, AdaptableUnaryFunction fun) |
|
{ |
|
return transform_iterator<AdaptableUnaryFunction, Iterator>(it, fun); |
|
} // end make_transform_iterator |
|
|
|
/*! \} // end fancyiterators |
|
*/ |
|
|
|
/*! \} // end iterators |
|
*/ |
|
|
|
} // end thrust |
|
|
|
|