/* * 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. */ #pragma once #include #include #include #include #include #include #include #include #include #include namespace thrust { // forward declare zip_iterator for zip_iterator_base template class zip_iterator; namespace detail { // Functors to be used with tuple algorithms // template class advance_iterator { public: inline __host__ __device__ advance_iterator(DiffType step) : m_step(step) {} template inline __host__ __device__ void operator()(Iterator& it) const { it += m_step; } private: DiffType m_step; }; // end advance_iterator struct increment_iterator { template inline __host__ __device__ void operator()(Iterator& it) { ++it; } }; // end increment_iterator struct decrement_iterator { template inline __host__ __device__ void operator()(Iterator& it) { --it; } }; // end decrement_iterator struct dereference_iterator { template struct apply { typedef typename iterator_traits::reference type; }; // end apply // XXX silence warnings of the form "calling a __host__ function from a __host__ __device__ function is not allowed __thrust_hd_warning_disable__ template __host__ __device__ typename apply::type operator()(Iterator const& it) { return *it; } }; // end dereference_iterator // The namespace tuple_impl_specific provides two meta- // algorithms and two algorithms for tuples. namespace tuple_impl_specific { // define apply1 for tuple_meta_transform_impl template struct apply1 : UnaryMetaFunctionClass::template apply { }; // end apply1 // define apply2 for tuple_meta_accumulate_impl template struct apply2 : UnaryMetaFunctionClass::template apply { }; // end apply2 // Meta-accumulate algorithm for tuples. Note: The template // parameter StartType corresponds to the initial value in // ordinary accumulation. // template struct tuple_meta_accumulate; template< typename Tuple , class BinaryMetaFun , typename StartType > struct tuple_meta_accumulate_impl { typedef typename apply2< BinaryMetaFun , typename Tuple::head_type , typename tuple_meta_accumulate< typename Tuple::tail_type , BinaryMetaFun , StartType >::type >::type type; }; template< typename Tuple , class BinaryMetaFun , typename StartType > struct tuple_meta_accumulate : thrust::detail::eval_if< thrust::detail::is_same::value , thrust::detail::identity_ , tuple_meta_accumulate_impl< Tuple , BinaryMetaFun , StartType > > // end eval_if { }; // end tuple_meta_accumulate // transform algorithm for tuples. The template parameter Fun // must be a unary functor which is also a unary metafunction // class that computes its return type based on its argument // type. For example: // // struct to_ptr // { // template // struct apply // { // typedef Arg* type; // } // // template // Arg* operator()(Arg x); // }; // for_each algorithm for tuples. // template inline __host__ __device__ Fun tuple_for_each(thrust::null_type, Fun f, System *) { return f; } // end tuple_for_each() template inline __host__ __device__ Fun tuple_for_each(Tuple& t, Fun f, System *dispatch_tag) { f( t.get_head() ); return tuple_for_each(t.get_tail(), f, dispatch_tag); } // end tuple_for_each() template inline __host__ __device__ Fun tuple_for_each(Tuple& t, Fun f, thrust::host_system_tag *dispatch_tag) { // XXX this path is required in order to accomodate pure host iterators // (such as std::vector::iterator) in a zip_iterator #ifndef __CUDA_ARCH__ f( t.get_head() ); return tuple_for_each(t.get_tail(), f, dispatch_tag); #else // this code will never be called return f; #endif } // end tuple_for_each() // Equality of tuples. NOTE: "==" for tuples currently (7/2003) // has problems under some compilers, so I just do my own. // No point in bringing in a bunch of #ifdefs here. This is // going to go away with the next tuple implementation anyway. // __host__ __device__ inline bool tuple_equal(thrust::null_type, thrust::null_type) { return true; } template __host__ __device__ bool tuple_equal(Tuple1 const& t1, Tuple2 const& t2) { return t1.get_head() == t2.get_head() && tuple_equal(t1.get_tail(), t2.get_tail()); } // end tuple_equal() } // end end tuple_impl_specific // Metafunction to obtain the type of the tuple whose element types // are the value_types of an iterator tupel. // template struct tuple_of_value_types : tuple_meta_transform< IteratorTuple, iterator_value > { }; // end tuple_of_value_types struct minimum_category_lambda { template struct apply : minimum_category {}; }; // Metafunction to obtain the minimal traversal tag in a tuple // of iterators. // template struct minimum_traversal_category_in_iterator_tuple { typedef typename tuple_meta_transform< IteratorTuple , thrust::iterator_traversal >::type tuple_of_traversal_tags; typedef typename tuple_impl_specific::tuple_meta_accumulate< tuple_of_traversal_tags , minimum_category_lambda , thrust::random_access_traversal_tag >::type type; }; struct minimum_system_lambda { template struct apply : minimum_system {}; }; // Metafunction to obtain the minimal system tag in a tuple // of iterators. template struct minimum_system_in_iterator_tuple { typedef typename thrust::detail::tuple_meta_transform< IteratorTuple, thrust::iterator_system >::type tuple_of_system_tags; typedef typename tuple_impl_specific::tuple_meta_accumulate< tuple_of_system_tags, minimum_system_lambda, thrust::any_system_tag >::type type; }; namespace zip_iterator_base_ns { template struct tuple_elements_helper : eval_if< (i < tuple_size::value), tuple_element, identity_ > {}; template struct tuple_elements { typedef typename tuple_elements_helper<0,Tuple>::type T0; typedef typename tuple_elements_helper<1,Tuple>::type T1; typedef typename tuple_elements_helper<2,Tuple>::type T2; typedef typename tuple_elements_helper<3,Tuple>::type T3; typedef typename tuple_elements_helper<4,Tuple>::type T4; typedef typename tuple_elements_helper<5,Tuple>::type T5; typedef typename tuple_elements_helper<6,Tuple>::type T6; typedef typename tuple_elements_helper<7,Tuple>::type T7; typedef typename tuple_elements_helper<8,Tuple>::type T8; typedef typename tuple_elements_helper<9,Tuple>::type T9; }; template struct tuple_of_iterator_references { // get a thrust::tuple of the iterators' references typedef typename tuple_meta_transform< IteratorTuple, iterator_reference >::type tuple_of_references; // get at the individual tuple element types by name typedef tuple_elements elements; // map thrust::tuple to tuple_of_iterator_references typedef thrust::detail::tuple_of_iterator_references< typename elements::T0, typename elements::T1, typename elements::T2, typename elements::T3, typename elements::T4, typename elements::T5, typename elements::T6, typename elements::T7, typename elements::T8, typename elements::T9 > type; }; } // end zip_iterator_base_ns /////////////////////////////////////////////////////////////////// // // Class zip_iterator_base // // Builds and exposes the iterator facade type from which the zip // iterator will be derived. // template struct zip_iterator_base { //private: // reference type is the type of the tuple obtained from the // iterators' reference types. typedef typename zip_iterator_base_ns::tuple_of_iterator_references::type reference; // Boost's Value type is the same as reference type. //typedef reference value_type; typedef typename tuple_of_value_types::type value_type; // Difference type is the first iterator's difference type typedef typename thrust::iterator_traits< typename thrust::tuple_element<0, IteratorTuple>::type >::difference_type difference_type; // Iterator system is the minimum system tag in the // iterator tuple typedef typename minimum_system_in_iterator_tuple::type system; // Traversal category is the minimum traversal category in the // iterator tuple typedef typename minimum_traversal_category_in_iterator_tuple::type traversal_category; public: // The iterator facade type from which the zip iterator will // be derived. typedef thrust::iterator_facade< zip_iterator, value_type, system, traversal_category, reference, difference_type > type; }; // end zip_iterator_base } // end detail } // end thrust