diff --git a/testing/allocator.cu b/testing/allocator.cu index 335014cdd..63984e006 100644 --- a/testing/allocator.cu +++ b/testing/allocator.cu @@ -56,8 +56,11 @@ DECLARE_UNITTEST(TestAllocatorCustomCopyConstruct); static int g_state; struct my_allocator_with_custom_destroy - : std::allocator { + typedef int value_type; + typedef int & reference; + typedef const int & const_reference; + template __host__ __device__ void destroy(T *p) @@ -66,6 +69,21 @@ struct my_allocator_with_custom_destroy g_state = 13; #endif } + + value_type *allocate(std::ptrdiff_t n) + { + return use_me_to_alloc.allocate(n); + } + + void deallocate(value_type *ptr, std::ptrdiff_t n) + { + use_me_to_alloc.deallocate(ptr,n); + } + + // use composition rather than inheritance + // to avoid inheriting std::allocator's member + // function construct + std::allocator use_me_to_alloc; }; void TestAllocatorCustomDestroy() @@ -79,3 +97,37 @@ void TestAllocatorCustomDestroy() } DECLARE_UNITTEST(TestAllocatorCustomDestroy); +struct my_minimal_allocator +{ + typedef int value_type; + + // XXX ideally, we shouldn't require + // these two typedefs + typedef int & reference; + typedef const int & const_reference; + + value_type *allocate(std::ptrdiff_t n) + { + return use_me_to_alloc.allocate(n); + } + + void deallocate(value_type *ptr, std::ptrdiff_t n) + { + use_me_to_alloc.deallocate(ptr,n); + } + + std::allocator use_me_to_alloc; +}; + +void TestAllocatorMinimal() +{ + thrust::cpp::vector vec(10, 13); + + // XXX copy to h_vec because ASSERT_EQUAL doesn't know about cpp::vector + thrust::host_vector h_vec(vec.begin(), vec.end()); + thrust::host_vector ref(10, 13); + + ASSERT_EQUAL(ref, h_vec); +} +DECLARE_UNITTEST(TestAllocatorMinimal); + diff --git a/thrust/detail/allocator/allocator_traits.h b/thrust/detail/allocator/allocator_traits.h index cb76f3e15..416ddf1bb 100644 --- a/thrust/detail/allocator/allocator_traits.h +++ b/thrust/detail/allocator/allocator_traits.h @@ -30,6 +30,8 @@ namespace allocator_traits_detail __THRUST_DEFINE_HAS_NESTED_TYPE(has_pointer, pointer); __THRUST_DEFINE_HAS_NESTED_TYPE(has_const_pointer, const_pointer); +__THRUST_DEFINE_HAS_NESTED_TYPE(has_reference, reference); +__THRUST_DEFINE_HAS_NESTED_TYPE(has_const_reference, const_reference); __THRUST_DEFINE_HAS_NESTED_TYPE(has_void_pointer, void_pointer); __THRUST_DEFINE_HAS_NESTED_TYPE(has_const_void_pointer, const_void_pointer); __THRUST_DEFINE_HAS_NESTED_TYPE(has_difference_type, difference_type); @@ -51,6 +53,18 @@ template typedef typename T::const_pointer type; }; +template + struct nested_reference +{ + typedef typename T::reference type; +}; + +template + struct nested_const_reference +{ + typedef typename T::const_reference type; +}; + template struct nested_void_pointer { diff --git a/thrust/detail/allocator/allocator_traits.inl b/thrust/detail/allocator/allocator_traits.inl index a98fada80..f95d08369 100644 --- a/thrust/detail/allocator/allocator_traits.inl +++ b/thrust/detail/allocator/allocator_traits.inl @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -27,17 +28,19 @@ namespace detail namespace allocator_traits_detail { -__THRUST_DEFINE_HAS_MEMBER_FUNCTION2(has_member_allocate_with_hint_impl, allocate); +__THRUST_DEFINE_IS_CALL_POSSIBLE(has_member_allocate_with_hint_impl, allocate) template - struct has_member_allocate_with_hint - : has_member_allocate_with_hint_impl< - Alloc, - typename allocator_traits::pointer, - typename allocator_traits::size_type, - typename allocator_traits::const_void_pointer - > -{}; + class has_member_allocate_with_hint +{ + typedef typename allocator_traits::pointer pointer; + typedef typename allocator_traits::size_type size_type; + typedef typename allocator_traits::const_void_pointer const_void_pointer; + + public: + typedef typename has_member_allocate_with_hint_impl::type type; + static const bool value = type::value; +}; template typename enable_if< @@ -60,15 +63,11 @@ template } -__THRUST_DEFINE_HAS_MEMBER_FUNCTION1(has_member_construct1_impl, construct); +__THRUST_DEFINE_IS_CALL_POSSIBLE(has_member_construct1_impl, construct) template struct has_member_construct1 - : has_member_construct1_impl< - Alloc, - void, - T* - > + : has_member_construct1_impl {}; template @@ -92,16 +91,11 @@ template } -__THRUST_DEFINE_HAS_MEMBER_FUNCTION2(has_member_construct2_impl, construct); +__THRUST_DEFINE_IS_CALL_POSSIBLE(has_member_construct2_impl, construct) template struct has_member_construct2 - : has_member_construct2_impl< - Alloc, - void, - T*, - const Arg1 & - > + : has_member_construct2_impl {}; template @@ -125,21 +119,17 @@ template } -__THRUST_DEFINE_HAS_MEMBER_FUNCTION1(has_member_destroy1_impl, destroy); +__THRUST_DEFINE_IS_CALL_POSSIBLE(has_member_destroy_impl, destroy) template - struct has_member_destroy1 - : has_member_destroy1_impl< - Alloc, - void, - T* - > + struct has_member_destroy + : has_member_destroy_impl {}; template inline __host__ __device__ typename enable_if< - has_member_destroy1::value + has_member_destroy::value >::type destroy(Alloc &a, T *p) { @@ -149,7 +139,7 @@ template template inline __host__ __device__ typename disable_if< - has_member_destroy1::value + has_member_destroy::value >::type destroy(Alloc &, T *p) { @@ -157,15 +147,17 @@ template } -__THRUST_DEFINE_HAS_MEMBER_FUNCTION0(has_member_max_size0_impl, max_size); +__THRUST_DEFINE_IS_CALL_POSSIBLE(has_member_max_size_impl, max_size); template - struct has_member_max_size - : has_member_max_size0_impl< - Alloc, - typename allocator_traits::size_type - > -{}; + class has_member_max_size +{ + typedef typename allocator_traits::size_type size_type; + + public: + typedef typename has_member_max_size_impl::type type; + static const bool value = type::value; +}; template typename enable_if< @@ -188,15 +180,17 @@ template return std::numeric_limits::max(); } -__THRUST_DEFINE_HAS_MEMBER_FUNCTION0(has_member_system0_impl, system); +__THRUST_DEFINE_HAS_MEMBER_FUNCTION(has_member_system_impl, system); template - struct has_member_system - : has_member_system0_impl< - Alloc, - typename allocator_system::type & - > -{}; + class has_member_system +{ + typedef typename allocator_system::type system_type; + + public: + typedef typename has_member_system_impl::type type; + static const bool value = type::value; +}; template typename enable_if< diff --git a/thrust/detail/allocator/copy_construct_range.h b/thrust/detail/allocator/copy_construct_range.h index da12ee886..ae9179b90 100644 --- a/thrust/detail/allocator/copy_construct_range.h +++ b/thrust/detail/allocator/copy_construct_range.h @@ -31,6 +31,13 @@ template + Pointer copy_construct_range_n(thrust::dispatchable &from_system, + Allocator &a, + InputIterator first, + Size n, + Pointer result); + } // end detail } // end thrust diff --git a/thrust/detail/allocator/copy_construct_range.inl b/thrust/detail/allocator/copy_construct_range.inl index ca5254140..ee117dcb9 100644 --- a/thrust/detail/allocator/copy_construct_range.inl +++ b/thrust/detail/allocator/copy_construct_range.inl @@ -24,7 +24,6 @@ #include #include #include -#include #include namespace thrust @@ -65,14 +64,19 @@ template // exactly from system::detail::generic::uninitialized_copy // perhaps generic::uninitialized_copy could call this routine // with a default allocator -template - Pointer uninitialized_copy_with_allocator(Allocator &a, - InputIterator first, - InputIterator last, - Pointer result) +template + typename enable_if_convertible< + FromSystem, + ToSystem, + Pointer + >::type + uninitialized_copy_with_allocator(Allocator &a, + thrust::dispatchable &from_system, + thrust::dispatchable &to_system, + InputIterator first, + InputIterator last, + Pointer result) { - typename allocator_system::type &system = allocator_system::get(a); - // zip up the iterators typedef thrust::tuple IteratorTuple; typedef thrust::zip_iterator ZipIterator; @@ -81,21 +85,96 @@ template ZipIterator end = begin; // get a zip_iterator pointing to the end - const typename thrust::iterator_difference::type n = thrust::distance(system,first,last); - thrust::advance(system,end,n); + const typename thrust::iterator_difference::type n = thrust::distance(from_system,first,last); + thrust::advance(from_system,end,n); // create a functor typedef typename iterator_traits::value_type InputType; typedef typename iterator_traits::value_type OutputType; // do the for_each - thrust::for_each(system, begin, end, copy_construct_with_allocator(a)); + // note we use to_system to dispatch the for_each + thrust::for_each(to_system, begin, end, copy_construct_with_allocator(a)); + + // return the end of the output range + return thrust::get<1>(end.get_iterator_tuple()); +} + + +// XXX it's regrettable that this implementation is copied almost +// exactly from system::detail::generic::uninitialized_copy_n +// perhaps generic::uninitialized_copy_n could call this routine +// with a default allocator +template + typename enable_if_convertible< + FromSystem, + ToSystem, + Pointer + >::type + uninitialized_copy_with_allocator_n(Allocator &a, + thrust::dispatchable &from_system, + thrust::dispatchable &to_system, + InputIterator first, + Size n, + Pointer result) +{ + // zip up the iterators + typedef thrust::tuple IteratorTuple; + typedef thrust::zip_iterator ZipIterator; + + ZipIterator begin = thrust::make_zip_iterator(thrust::make_tuple(first,result)); + + // create a functor + typedef typename iterator_traits::value_type InputType; + typedef typename iterator_traits::value_type OutputType; + + // do the for_each_n + // note we use to_system to dispatch the for_each_n + ZipIterator end = thrust::for_each_n(to_system, begin, n, copy_construct_with_allocator(a)); // return the end of the output range return thrust::get<1>(end.get_iterator_tuple()); } +template + typename disable_if_convertible< + FromSystem, + ToSystem, + Pointer + >::type + uninitialized_copy_with_allocator(Allocator &, + thrust::dispatchable &from_system, + thrust::dispatchable &to_system, + InputIterator first, + InputIterator last, + Pointer result) +{ + // the systems aren't trivially interoperable + // just call two_system_copy and hope for the best + return thrust::detail::two_system_copy(from_system, to_system, first, last, result); +} // end uninitialized_copy_with_allocator() + + +template + typename disable_if_convertible< + FromSystem, + ToSystem, + Pointer + >::type + uninitialized_copy_with_allocator_n(Allocator &, + thrust::dispatchable &from_system, + thrust::dispatchable &to_system, + InputIterator first, + Size n, + Pointer result) +{ + // the systems aren't trivially interoperable + // just call two_system_copy_n and hope for the best + return thrust::detail::two_system_copy_n(from_system, to_system, first, n, result); +} // end uninitialized_copy_with_allocator_n() + + template struct is_trivially_copy_constructible : integral_constant< @@ -133,6 +212,27 @@ template + typename enable_if< + is_trivially_copy_constructible< + Allocator, + typename pointer_element::type + >::value, + Pointer + >::type + copy_construct_range_n(thrust::dispatchable &from_system, + Allocator &a, + InputIterator first, + Size n, + Pointer result) +{ + typename allocator_system::type &to_system = allocator_system::get(a); + + // just call two_system_copy_n + return thrust::detail::two_system_copy_n(from_system, to_system, first, n, result); +} + + template typename disable_if< is_trivially_copy_constructible< @@ -147,13 +247,27 @@ template::type ToSystem; - ToSystem &to_system = allocator_system::get(a); + typename allocator_system::type &to_system = allocator_system::get(a); + return uninitialized_copy_with_allocator(a, from_system, to_system, first, last, result); +} - // move input to the same system as the output - thrust::detail::move_to_system temp(from_system,to_system,first,last); - return uninitialized_copy_with_allocator(a, temp.begin(), temp.end(), result); +template + typename disable_if< + is_trivially_copy_constructible< + Allocator, + typename pointer_element::type + >::value, + Pointer + >::type + copy_construct_range_n(thrust::dispatchable &from_system, + Allocator &a, + InputIterator first, + Size n, + Pointer result) +{ + typename allocator_system::type &to_system = allocator_system::get(a); + return uninitialized_copy_with_allocator_n(a, from_system, to_system, first, n, result); } @@ -171,6 +285,17 @@ template + Pointer copy_construct_range_n(thrust::dispatchable &from_system, + Allocator &a, + InputIterator first, + Size n, + Pointer result) +{ + return allocator_traits_detail::copy_construct_range_n(from_system, a, first, n, result); +} + + } // end detail } // end thrust diff --git a/thrust/detail/allocator/destroy_range.inl b/thrust/detail/allocator/destroy_range.inl index f13ce6b31..ace222356 100644 --- a/thrust/detail/allocator/destroy_range.inl +++ b/thrust/detail/allocator/destroy_range.inl @@ -36,13 +36,13 @@ namespace allocator_traits_detail // 3. if T has a trivial destructor, do a no-op template - struct has_effectful_member_destroy1 - : has_member_destroy1 + struct has_effectful_member_destroy + : has_member_destroy {}; // std::allocator::destroy's only effect is to invoke its argument's destructor template - struct has_effectful_member_destroy1, T> + struct has_effectful_member_destroy, T> : thrust::detail::false_type {}; @@ -50,7 +50,7 @@ template template struct enable_if_destroy_range_case1 : thrust::detail::enable_if< - has_effectful_member_destroy1< + has_effectful_member_destroy< Allocator, typename pointer_element::type >::value @@ -61,7 +61,7 @@ template template struct enable_if_destroy_range_case2 : thrust::detail::enable_if< - !has_effectful_member_destroy1< + !has_effectful_member_destroy< Allocator, typename pointer_element::type >::value && @@ -75,7 +75,7 @@ template template struct enable_if_destroy_range_case3 : thrust::detail::enable_if< - !has_effectful_member_destroy1< + !has_effectful_member_destroy< Allocator, typename pointer_element::type >::value && diff --git a/thrust/detail/contiguous_storage.h b/thrust/detail/contiguous_storage.h index addf96f3f..75316283f 100644 --- a/thrust/detail/contiguous_storage.h +++ b/thrust/detail/contiguous_storage.h @@ -18,6 +18,7 @@ #include #include +#include namespace thrust { @@ -29,15 +30,24 @@ namespace detail template class contiguous_storage { + private: + typedef thrust::detail::allocator_traits alloc_traits; + public: - typedef Alloc allocator_type; - typedef T value_type; - typedef typename allocator_type::pointer pointer; - typedef typename allocator_type::const_pointer const_pointer; - typedef typename allocator_type::reference reference; - typedef typename allocator_type::const_reference const_reference; - typedef typename allocator_type::size_type size_type; - typedef typename allocator_type::difference_type difference_type; + typedef Alloc allocator_type; + typedef T value_type; + typedef typename alloc_traits::pointer pointer; + typedef typename alloc_traits::const_pointer const_pointer; + typedef typename alloc_traits::size_type size_type; + typedef typename alloc_traits::difference_type difference_type; + + // XXX we should bring reference & const_reference into allocator_traits + // at the moment, it's unclear how -- we have nothing analogous to + // rebind_pointer for references + // we either need to add reference_traits or extend the existing + // pointer_traits to support wrapped references + typedef typename Alloc::reference reference; + typedef typename Alloc::const_reference const_reference; typedef thrust::detail::normal_iterator iterator; typedef thrust::detail::normal_iterator const_iterator; @@ -86,6 +96,15 @@ template InputIterator last, iterator result); + template + iterator uninitialized_copy_n(InputIterator first, Size n, iterator result); + + template + iterator uninitialized_copy_n(thrust::dispatchable &from_system, + InputIterator first, + Size n, + iterator result); + void destroy(iterator first, iterator last); private: diff --git a/thrust/detail/contiguous_storage.inl b/thrust/detail/contiguous_storage.inl index d95978ddb..1490e048d 100644 --- a/thrust/detail/contiguous_storage.inl +++ b/thrust/detail/contiguous_storage.inl @@ -71,7 +71,7 @@ template contiguous_storage ::max_size(void) const { - return m_allocator.max_size(); + return alloc_traits::max_size(m_allocator); } // end contiguous_storage::max_size() template @@ -205,6 +205,27 @@ template return iterator(copy_construct_range(from_system, m_allocator, first, last, result.base())); } // end contiguous_storage::uninitialized_copy() +template + template + typename contiguous_storage::iterator + contiguous_storage + ::uninitialized_copy_n(thrust::dispatchable &from_system, InputIterator first, Size n, iterator result) +{ + return iterator(copy_construct_range_n(from_system, m_allocator, first, n, result.base())); +} // end contiguous_storage::uninitialized_copy_n() + +template + template + typename contiguous_storage::iterator + contiguous_storage + ::uninitialized_copy_n(InputIterator first, Size n, iterator result) +{ + // XXX assumes InputIterator's associated System is default-constructible + typename thrust::iterator_system::type from_system; + + return iterator(copy_construct_range_n(from_system, m_allocator, first, n, result.base())); +} // end contiguous_storage::uninitialized_copy_n() + template void contiguous_storage ::destroy(iterator first, iterator last) diff --git a/thrust/detail/temporary_array.inl b/thrust/detail/temporary_array.inl index a2fbba0da..eccf168e7 100644 --- a/thrust/detail/temporary_array.inl +++ b/thrust/detail/temporary_array.inl @@ -17,7 +17,6 @@ #include #include #include -#include #include @@ -87,8 +86,7 @@ template { super_t::allocate(n); - // XXX this copy should actually be copy construct via allocator - thrust::copy_n(system, first, n, super_t::begin()); + super_t::uninitialized_copy_n(system, first, n, super_t::begin()); } // end temporary_array::temporary_array() @@ -103,8 +101,7 @@ template { super_t::allocate(n); - // XXX this copy should actually be copy construct via allocator - thrust::detail::two_system_copy_n(input_system, system, first, n, super_t::begin()); + super_t::uninitialized_copy_n(input_system, first, n, super_t::begin()); } // end temporary_array::temporary_array() @@ -118,8 +115,7 @@ template { super_t::allocate(thrust::distance(system,first,last)); - // XXX this copy should actually be copy construct via allocator - thrust::copy(system, first, last, super_t::begin()); + super_t::uninitialized_copy(system, first, last, super_t::begin()); } // end temporary_array::temporary_array() @@ -134,8 +130,7 @@ template { super_t::allocate(thrust::distance(input_system,first,last)); - // XXX this copy should actually be copy construct via allocator - thrust::detail::two_system_copy(input_system, system, first, last, super_t::begin()); + super_t::uninitialized_copy(input_system, first, last, super_t::begin()); } // end temporary_array::temporary_array() diff --git a/thrust/detail/type_traits.h b/thrust/detail/type_traits.h index 6daa636ea..5dbeb906e 100644 --- a/thrust/detail/type_traits.h +++ b/thrust/detail/type_traits.h @@ -443,6 +443,12 @@ template {}; +template + struct disable_if_convertible + : disable_if< is_convertible::value, T > +{}; + + template struct enable_if_different : enable_if::value, Result> diff --git a/thrust/detail/type_traits/has_member_function.h b/thrust/detail/type_traits/has_member_function.h index cbb74bfb2..117f4cb9b 100644 --- a/thrust/detail/type_traits/has_member_function.h +++ b/thrust/detail/type_traits/has_member_function.h @@ -18,67 +18,101 @@ #include -#define __THRUST_DEFINE_HAS_MONOMORPHIC_MEMBER_FUNCTION(trait_name, member_function_name) \ -template \ - struct trait_name \ -{ \ - typedef char yes_type; \ - typedef struct {yes_type array[2];} no_type; \ - template static yes_type test(char (*)[sizeof(&S::member_function_name)]); \ - template static no_type test(...); \ - static bool const value = sizeof(test(0)) == sizeof(yes_type); \ - typedef thrust::detail::integral_constant type; \ -}; - -#define __THRUST_DEFINE_HAS_MEMBER_FUNCTION0(trait_name, member_function_name) \ -template \ - struct trait_name \ -{ \ - typedef char yes_type; \ - typedef struct {yes_type array[2];} no_type; \ - template struct check; \ - template static yes_type test(check *); \ - template static no_type test(...); \ - static bool const value = sizeof(test(0)) == sizeof(yes_type); \ - typedef thrust::detail::integral_constant type; \ -}; - -#define __THRUST_DEFINE_HAS_MEMBER_FUNCTION1(trait_name, member_function_name) \ -template \ - struct trait_name \ -{ \ - typedef char yes_type; \ - typedef struct {yes_type array[2];} no_type; \ - template struct check; \ - template static yes_type test(check *); \ - template static no_type test(...); \ - static bool const value = sizeof(test(0)) == sizeof(yes_type); \ - typedef thrust::detail::integral_constant type; \ -}; - -#define __THRUST_DEFINE_HAS_MEMBER_FUNCTION2(trait_name, member_function_name) \ -template \ - struct trait_name \ -{ \ - typedef char yes_type; \ - typedef struct {yes_type array[2];} no_type; \ - template struct check; \ - template static yes_type test(check *); \ - template static no_type test(...); \ - static bool const value = sizeof(test(0)) == sizeof(yes_type); \ - typedef thrust::detail::integral_constant type; \ -}; - -#define __THRUST_DEFINE_HAS_MEMBER_FUNCTION3(trait_name, member_function_name) \ -template \ - struct trait_name \ -{ \ - typedef char yes_type; \ - typedef struct {yes_type array[2];} no_type; \ - template struct check; \ - template static yes_type test(check *); \ - template static no_type test(...); \ - static bool const value = sizeof(test(0)) == sizeof(yes_type); \ - typedef thrust::detail::integral_constant type; \ -}; +#define __THRUST_DEFINE_HAS_MEMBER_FUNCTION(trait_name, member_function_name) \ +template class trait_name; \ + \ +template \ +class trait_name \ +{ \ + class yes { char m; }; \ + class no { yes m[2]; }; \ + struct base_mixin \ + { \ + Result member_function_name(); \ + }; \ + struct base : public T, public base_mixin {}; \ + template class helper{}; \ + template \ + static no deduce(U*, helper* = 0); \ + static yes deduce(...); \ +public: \ + static const bool value = sizeof(yes) == sizeof(deduce(static_cast(0))); \ + typedef thrust::detail::integral_constant type; \ +}; \ + \ +template \ +class trait_name \ +{ \ + class yes { char m; }; \ + class no { yes m[2]; }; \ + struct base_mixin \ + { \ + Result member_function_name(Arg); \ + }; \ + struct base : public T, public base_mixin {}; \ + template class helper{}; \ + template \ + static no deduce(U*, helper* = 0); \ + static yes deduce(...); \ +public: \ + static const bool value = sizeof(yes) == sizeof(deduce(static_cast(0))); \ + typedef thrust::detail::integral_constant type; \ +}; \ + \ +template \ +class trait_name \ +{ \ + class yes { char m; }; \ + class no { yes m[2]; }; \ + struct base_mixin \ + { \ + Result member_function_name(Arg1,Arg2); \ + }; \ + struct base : public T, public base_mixin {}; \ + template class helper{}; \ + template \ + static no deduce(U*, helper* = 0); \ + static yes deduce(...); \ +public: \ + static const bool value = sizeof(yes) == sizeof(deduce(static_cast(0))); \ + typedef thrust::detail::integral_constant type; \ +}; \ + \ +template \ +class trait_name \ +{ \ + class yes { char m; }; \ + class no { yes m[2]; }; \ + struct base_mixin \ + { \ + Result member_function_name(Arg1,Arg2,Arg3); \ + }; \ + struct base : public T, public base_mixin {}; \ + template class helper{}; \ + template \ + static no deduce(U*, helper* = 0); \ + static yes deduce(...); \ +public: \ + static const bool value = sizeof(yes) == sizeof(deduce(static_cast(0))); \ + typedef thrust::detail::integral_constant type; \ +}; \ + \ +template \ +class trait_name \ +{ \ + class yes { char m; }; \ + class no { yes m[2]; }; \ + struct base_mixin \ + { \ + Result member_function_name(Arg1,Arg2,Arg3,Arg4); \ + }; \ + struct base : public T, public base_mixin {}; \ + template class helper{}; \ + template \ + static no deduce(U*, helper* = 0); \ + static yes deduce(...); \ +public: \ + static const bool value = sizeof(yes) == sizeof(deduce(static_cast(0))); \ + typedef thrust::detail::integral_constant type; \ +}; diff --git a/thrust/detail/type_traits/is_call_possible.h b/thrust/detail/type_traits/is_call_possible.h new file mode 100644 index 000000000..41b9539e1 --- /dev/null +++ b/thrust/detail/type_traits/is_call_possible.h @@ -0,0 +1,161 @@ +/* + * 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 + +// inspired by Roman Perepelitsa's presentation from comp.lang.c++.moderated +// based on the implementation here: http://www.rsdn.ru/forum/cpp/2759773.1.aspx + +namespace thrust +{ +namespace detail +{ +namespace is_call_possible_detail +{ + +template class void_exp_result {}; + +template +U const& operator,(U const&, void_exp_result); + +template +U& operator,(U&, void_exp_result); + +template +struct clone_constness +{ + typedef dest_type type; +}; + +template +struct clone_constness +{ + typedef const dest_type type; +}; + +} // end is_call_possible_detail +} // end detail +} // end thrust + +#define __THRUST_DEFINE_IS_CALL_POSSIBLE(trait_name, member_function_name) \ +__THRUST_DEFINE_HAS_MEMBER_FUNCTION(trait_name##_has_member, member_function_name) \ + \ +template \ +struct trait_name \ +{ \ + private: \ + struct yes {}; \ + struct no { yes m[2]; }; \ + struct derived : public T \ + { \ + using T::member_function_name; \ + no member_function_name(...) const; \ + }; \ + \ + typedef typename thrust::detail::is_call_possible_detail::clone_constness::type derived_type; \ + \ + template \ + struct return_value_check \ + { \ + static yes deduce(Result); \ + static no deduce(...); \ + static no deduce(no); \ + static no deduce(thrust::detail::is_call_possible_detail::void_exp_result); \ + }; \ + \ + template \ + struct return_value_check \ + { \ + static yes deduce(...); \ + static no deduce(no); \ + }; \ + \ + template \ + struct impl \ + { \ + static const bool value = false; \ + }; \ + \ + template \ + struct impl \ + { \ + static typename add_reference::type test_me; \ + static typename add_reference::type arg; \ + \ + static const bool value = \ + sizeof( \ + return_value_check::deduce( \ + (test_me.member_function_name(arg), thrust::detail::is_call_possible_detail::void_exp_result()) \ + ) \ + ) == sizeof(yes); \ + }; \ + \ + template \ + struct impl \ + { \ + static typename add_reference::type test_me; \ + static typename add_reference::type arg1; \ + static typename add_reference::type arg2; \ + \ + static const bool value = \ + sizeof( \ + return_value_check::deduce( \ + (test_me.member_function_name(arg1,arg2), thrust::detail::is_call_possible_detail::void_exp_result()) \ + ) \ + ) == sizeof(yes); \ + }; \ + \ + template \ + struct impl \ + { \ + static typename add_reference::type test_me; \ + static typename add_reference::type arg1; \ + static typename add_reference::type arg2; \ + static typename add_reference::type arg3; \ + \ + static const bool value = \ + sizeof( \ + return_value_check::deduce( \ + (test_me.member_function_name(arg1,arg2,arg3), thrust::detail::is_call_possible_detail::void_exp_result()) \ + ) \ + ) == sizeof(yes); \ + }; \ + \ + template \ + struct impl \ + { \ + static typename add_reference::type test_me; \ + static typename add_reference::type arg1; \ + static typename add_reference::type arg2; \ + static typename add_reference::type arg3; \ + static typename add_reference::type arg4; \ + \ + static const bool value = \ + sizeof( \ + return_value_check::deduce( \ + (test_me.member_function_name(arg1,arg2,arg3,arg4), thrust::detail::is_call_possible_detail::void_exp_result()) \ + ) \ + ) == sizeof(yes); \ + }; \ + \ + public: \ + static const bool value = impl::value, Signature>::value; \ + typedef thrust::detail::integral_constant type; \ +}; +