/* * 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. */ #pragma once #include #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 #include #include #include // the order of declarations and definitions in this file is totally goofy // this header defines raw_reference_cast, which has a few overloads towards the bottom of the file // raw_reference_cast depends on metafunctions such as is_unwrappable and raw_reference // we need to be sure that these metafunctions are completely defined (including specializations) before they are // instantiated by raw_reference_cast THRUST_NAMESPACE_BEGIN namespace detail { template class tuple_of_iterator_references; __THRUST_DEFINE_HAS_NESTED_TYPE(is_wrapped_reference, wrapped_reference_hint) // wrapped reference-like things which aren't strictly wrapped references // (e.g. tuples of wrapped references) are considered unwrappable template struct is_unwrappable : is_wrapped_reference {}; // specialize is_unwrappable // a tuple is_unwrappable if any of its elements is_unwrappable template struct is_unwrappable> : ::cuda::std::disjunction...> {}; // specialize is_unwrappable // a tuple_of_iterator_references is_unwrappable if any of its elements is_unwrappable template struct is_unwrappable> : ::cuda::std::disjunction...> {}; template struct enable_if_unwrappable : ::cuda::std::enable_if::value, Result> {}; namespace raw_reference_detail { template struct raw_reference_impl : ::cuda::std::add_lvalue_reference {}; template struct raw_reference_impl>::value>> { typedef ::cuda::std::__add_lvalue_reference_t::type> type; }; } // namespace raw_reference_detail template struct raw_reference : raw_reference_detail::raw_reference_impl {}; namespace raw_reference_detail { // unlike raw_reference, // raw_reference_tuple_helper needs to return a value // when it encounters one, rather than a reference // upon encountering tuple, recurse // // we want the following behavior: // 1. T -> T // 2. T& -> T& // 3. null_type -> null_type // 4. reference -> T& // 5. tuple_of_iterator_references -> tuple_of_iterator_references::type> // wrapped references are unwrapped using raw_reference, otherwise, return T template struct raw_reference_tuple_helper : eval_if>::value, raw_reference, identity_> {}; // recurse on tuples template struct raw_reference_tuple_helper> { typedef thrust::tuple::type...> type; }; template struct raw_reference_tuple_helper> { typedef thrust::detail::tuple_of_iterator_references::type...> type; }; } // namespace raw_reference_detail // a couple of specializations of raw_reference for tuples follow // if a tuple "tuple_type" is_unwrappable, // then the raw_reference of tuple_type is a tuple of its members' raw_references // else the raw_reference of tuple_type is tuple_type & template struct raw_reference> { private: typedef thrust::tuple tuple_type; public: typedef typename eval_if::value, raw_reference_detail::raw_reference_tuple_helper, ::cuda::std::add_lvalue_reference>::type type; }; template struct raw_reference> { private: typedef detail::tuple_of_iterator_references tuple_type; public: typedef typename raw_reference_detail::raw_reference_tuple_helper::type type; }; } // namespace detail // provide declarations of raw_reference_cast's overloads for raw_reference_caster below template _CCCL_HOST_DEVICE typename detail::raw_reference::type raw_reference_cast(T& ref); template _CCCL_HOST_DEVICE typename detail::raw_reference::type raw_reference_cast(const T& ref); template _CCCL_HOST_DEVICE typename detail::enable_if_unwrappable< thrust::detail::tuple_of_iterator_references, typename detail::raw_reference>::type>::type raw_reference_cast(thrust::detail::tuple_of_iterator_references t); namespace detail { struct raw_reference_caster { template _CCCL_HOST_DEVICE typename detail::raw_reference::type operator()(T& ref) { return thrust::raw_reference_cast(ref); } template _CCCL_HOST_DEVICE typename detail::raw_reference::type operator()(const T& ref) { return thrust::raw_reference_cast(ref); } template _CCCL_HOST_DEVICE typename detail::raw_reference>::type operator()(thrust::detail::tuple_of_iterator_references t, ::cuda::std::__enable_if_t>::value>* = 0) { return thrust::raw_reference_cast(t); } }; // end raw_reference_caster } // namespace detail template _CCCL_HOST_DEVICE typename detail::raw_reference::type raw_reference_cast(T& ref) { return *thrust::raw_pointer_cast(&ref); } // end raw_reference_cast template _CCCL_HOST_DEVICE typename detail::raw_reference::type raw_reference_cast(const T& ref) { return *thrust::raw_pointer_cast(&ref); } // end raw_reference_cast template _CCCL_HOST_DEVICE typename detail::enable_if_unwrappable< thrust::detail::tuple_of_iterator_references, typename detail::raw_reference>::type>::type raw_reference_cast(thrust::detail::tuple_of_iterator_references t) { thrust::detail::raw_reference_caster f; // note that we pass raw_reference_tuple_helper, not raw_reference as the unary metafunction // the different way that raw_reference_tuple_helper unwraps tuples is important return thrust::detail::tuple_host_device_transform(t, f); } // end raw_reference_cast THRUST_NAMESPACE_END