#include #include #include #include #include #include // WAR NVIDIA/cccl#1731 // Some tests miscompile for non-CUDA backends on MSVC 2017 and 2019 (though 2022 is fine). // This is due to a bug in the compiler that breaks __THRUST_DEFINE_HAS_MEMBER_FUNCTION. #if defined(_MSC_VER) && _MSC_VER <= 1929 && THRUST_DEVICE_SYSTEM != THRUST_DEVICE_SYSTEM_CUDA # define WAR_BUG_1731 #endif // The needs_copy_construct_via_allocator trait depends on has_member_function: #ifndef WAR_BUG_1731 template struct my_allocator_with_custom_construct1 : thrust::device_malloc_allocator { my_allocator_with_custom_construct1() = default; _CCCL_HOST_DEVICE void construct(T* p) { *p = 13; } }; template void TestAllocatorCustomDefaultConstruct(size_t n) { thrust::device_vector ref(n, 13); thrust::device_vector> vec(n); ASSERT_EQUAL_QUIET(ref, vec); } DECLARE_VARIABLE_UNITTEST(TestAllocatorCustomDefaultConstruct); template struct my_allocator_with_custom_construct2 : thrust::device_malloc_allocator { my_allocator_with_custom_construct2() = default; template _CCCL_HOST_DEVICE void construct(T* p, const Arg&) { *p = 13; } }; template void TestAllocatorCustomCopyConstruct(size_t n) { thrust::device_vector ref(n, 13); thrust::device_vector copy_from(n, 7); thrust::device_vector> vec(copy_from.begin(), copy_from.end()); ASSERT_EQUAL_QUIET(ref, vec); } DECLARE_VARIABLE_UNITTEST(TestAllocatorCustomCopyConstruct); #endif // !WAR_BUG_1731 // The has_member_destroy trait depends on has_member_function: #ifndef WAR_BUG_1731 template struct my_allocator_with_custom_destroy { // This is only used with thrust::cpp::vector: using system_type = thrust::cpp::tag; using value_type = T; using reference = T&; using const_reference = const T&; static bool g_state; _CCCL_HOST my_allocator_with_custom_destroy() {} // NOLINT(modernize-use-equals-default) _CCCL_HOST my_allocator_with_custom_destroy(const my_allocator_with_custom_destroy& other) : use_me_to_alloc(other.use_me_to_alloc) {} _CCCL_HOST ~my_allocator_with_custom_destroy() {} // NOLINT(modernize-use-equals-default) _CCCL_HOST_DEVICE void destroy(T*) noexcept { NV_IF_TARGET(NV_IS_HOST, (g_state = true;)); } value_type* allocate(std::ptrdiff_t n) { return use_me_to_alloc.allocate(n); } void deallocate(value_type* ptr, std::ptrdiff_t n) noexcept { use_me_to_alloc.deallocate(ptr, n); } bool operator==(const my_allocator_with_custom_destroy&) const { return true; } bool operator!=(const my_allocator_with_custom_destroy& other) const { return !(*this == other); } using is_always_equal = thrust::detail::true_type; // use composition rather than inheritance // to avoid inheriting std::allocator's member // function destroy std::allocator use_me_to_alloc; }; template bool my_allocator_with_custom_destroy::g_state = false; template void TestAllocatorCustomDestroy(size_t n) { my_allocator_with_custom_destroy::g_state = false; { thrust::cpp::vector> vec(n); } // destroy everything // state should only be true when there are values to destroy: ASSERT_EQUAL(n > 0, my_allocator_with_custom_destroy::g_state); } DECLARE_VARIABLE_UNITTEST(TestAllocatorCustomDestroy); #endif // !WAR_BUG_1731 template struct my_minimal_allocator { using value_type = T; // XXX ideally, we shouldn't require these two aliases using reference = T&; using const_reference = const T&; _CCCL_HOST my_minimal_allocator() {} // NOLINT(modernize-use-equals-default) _CCCL_HOST my_minimal_allocator(const my_minimal_allocator& other) : use_me_to_alloc(other.use_me_to_alloc) {} _CCCL_HOST ~my_minimal_allocator() {} // NOLINT(modernize-use-equals-default) value_type* allocate(std::ptrdiff_t n) { return use_me_to_alloc.allocate(n); } void deallocate(value_type* ptr, std::ptrdiff_t n) noexcept { use_me_to_alloc.deallocate(ptr, n); } std::allocator use_me_to_alloc; }; template void TestAllocatorMinimal(size_t n) { thrust::cpp::vector> vec(n, 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(n, 13); ASSERT_EQUAL(ref, h_vec); } DECLARE_VARIABLE_UNITTEST(TestAllocatorMinimal); void TestAllocatorTraitsRebind() { ASSERT_EQUAL( (::cuda::std::is_same< typename cuda::std::allocator_traits>::template rebind_traits, typename cuda::std::allocator_traits>>::value), true); ASSERT_EQUAL( (::cuda::std::is_same>::template rebind_traits, typename cuda::std::allocator_traits>>::value), true); } DECLARE_UNITTEST(TestAllocatorTraitsRebind); void TestAllocatorTraitsRebindCpp11() { ASSERT_EQUAL( (::cuda::std::is_same< typename cuda::std::allocator_traits>::template rebind_alloc, thrust::device_malloc_allocator>::value), true); ASSERT_EQUAL( (::cuda::std::is_same>::template rebind_alloc, my_minimal_allocator>::value), true); ASSERT_EQUAL( (::cuda::std::is_same< typename cuda::std::allocator_traits>::template rebind_traits, typename cuda::std::allocator_traits>>::value), true); ASSERT_EQUAL( (::cuda::std::is_same>::template rebind_traits, typename cuda::std::allocator_traits>>::value), true); } DECLARE_UNITTEST(TestAllocatorTraitsRebindCpp11);