1 /* 2 Copyright (c) 2005-2021 Intel Corporation 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 #ifndef __TBB_test_common_containers_common_H 18 #define __TBB_test_common_containers_common_H 19 20 #include "config.h" 21 #include "custom_allocators.h" 22 23 template <typename ContainerType> 24 void test_allocator_traits() { 25 using allocator_type = typename ContainerType::allocator_type; 26 using allocator_traits_type = std::allocator_traits<allocator_type>; 27 using pocca_type = typename allocator_traits_type::propagate_on_container_copy_assignment; 28 using pocma_type = typename allocator_traits_type::propagate_on_container_move_assignment; 29 using pocs_type = typename allocator_traits_type::propagate_on_container_swap; 30 31 bool propagated_on_copy = false; 32 bool propagated_on_move = false; 33 bool propagated_on_swap = false; 34 bool selected_on_copy = false; 35 36 allocator_type alloc(propagated_on_copy, propagated_on_move, propagated_on_swap, selected_on_copy); 37 38 ContainerType c1(alloc), c2(c1); 39 REQUIRE_MESSAGE(selected_on_copy, "select_on_container_copy_construction function was not called"); 40 41 c1 = c2; 42 REQUIRE_MESSAGE(propagated_on_copy == pocca_type::value, "Unexpected allocator propagation on copy assignment"); 43 44 c2 = std::move(c1); 45 REQUIRE_MESSAGE(propagated_on_move == pocma_type::value, "Unexpected allocator propagation on move assignment"); 46 47 c1.swap(c2); 48 REQUIRE_MESSAGE(propagated_on_swap == pocs_type::value, "Unexpected allocator propagation on swap"); 49 50 propagated_on_move = false; 51 propagated_on_swap = false; 52 using std::swap; 53 swap(c1, c2); 54 REQUIRE_MESSAGE(propagated_on_move == false, "Unexpected allocator propagation on non-member swap"); 55 REQUIRE_MESSAGE(propagated_on_swap == pocs_type::value, "Unexpected allocator propagation on non-member swap"); 56 } 57 58 struct NonMovableObject { 59 NonMovableObject() = default; 60 NonMovableObject( const NonMovableObject& ) = delete; 61 NonMovableObject( NonMovableObject&& ) = delete; 62 NonMovableObject& operator=( const NonMovableObject& ) = delete; 63 NonMovableObject& operator=( NonMovableObject&& ) = delete; 64 }; 65 66 namespace std { 67 template <> 68 struct hash<NonMovableObject> { 69 std::size_t operator()( const NonMovableObject& ) { return 1; } 70 }; 71 } 72 73 template <typename ContainerType> 74 void test_allocator_traits_with_non_movable_value_type() { 75 // Check that if pocma is true, container allows move assignment without per-element move 76 using allocator_type = typename ContainerType::allocator_type; 77 using allocator_traits_type = std::allocator_traits<allocator_type>; 78 using pocma_type = typename allocator_traits_type::propagate_on_container_move_assignment; 79 REQUIRE_MESSAGE(pocma_type::value, "Allocator POCMA should be true for this test"); 80 allocator_type alloc; 81 ContainerType container1(alloc), container2(alloc); 82 container1 = std::move(container2); 83 } 84 85 template <typename ContainerType> 86 void test_is_always_equal() { 87 using allocator_type = typename ContainerType::allocator_type; 88 allocator_type alloc; 89 90 ContainerType container1(alloc), container2(std::move(container1), alloc); 91 92 container1 = std::move(container2); 93 94 container1.swap(container2); 95 96 using std::swap; 97 swap(container1, container2); 98 } 99 100 template <typename ContainerTraits> 101 void test_allocator_traits_support() { 102 using container_value_type = typename ContainerTraits::template container_value_type<int>; 103 104 using always_propagating_allocator_type = AlwaysPropagatingAllocator<container_value_type>; 105 using never_propagating_allocator_type = NeverPropagatingAllocator<container_value_type>; 106 using pocma_allocator_type = PocmaAllocator<container_value_type>; 107 using pocca_allocator_type = PoccaAllocator<container_value_type>; 108 using pocs_allocator_type = PocsAllocator<container_value_type>; 109 using always_equal_allocator_type = AlwaysEqualAllocator<container_value_type>; 110 111 using always_container_type = typename ContainerTraits::template container_type<int, always_propagating_allocator_type>; 112 using never_container_type = typename ContainerTraits::template container_type<int, never_propagating_allocator_type>; 113 using pocma_container_type = typename ContainerTraits::template container_type<int, pocma_allocator_type>; 114 using pocca_container_type = typename ContainerTraits::template container_type<int, pocca_allocator_type>; 115 using pocs_container_type = typename ContainerTraits::template container_type<int, pocs_allocator_type>; 116 using always_equal_container_type = typename ContainerTraits::template container_type<int, always_equal_allocator_type>; 117 118 test_allocator_traits<always_container_type>(); 119 test_allocator_traits<never_container_type>(); 120 test_allocator_traits<pocma_container_type>(); 121 test_allocator_traits<pocca_container_type>(); 122 test_allocator_traits<pocs_container_type>(); 123 124 using container_non_movable_value_type = typename ContainerTraits::template container_value_type<NonMovableObject>; 125 using pocma_allocator_non_movable_value_type = PocmaAllocator<container_non_movable_value_type>; 126 using pocma_container_non_movable_value_type = typename ContainerTraits::template 127 container_type<NonMovableObject, pocma_allocator_non_movable_value_type>; 128 test_allocator_traits_with_non_movable_value_type<pocma_container_non_movable_value_type>(); 129 test_is_always_equal<always_equal_container_type>(); 130 } 131 132 #if TBB_USE_EXCEPTIONS 133 struct ThrowOnCopy { 134 static int error_code() { return 8; }; 135 static bool is_active; 136 ThrowOnCopy() = default; 137 ThrowOnCopy( const ThrowOnCopy& ) { 138 if (is_active) { 139 throw error_code(); 140 } 141 } 142 static void activate() { is_active = true; } 143 static void deactivate() { is_active = false; } 144 145 bool operator<( const ThrowOnCopy& ) const { return true; } 146 bool operator==( const ThrowOnCopy& ) const { return true; } 147 }; // struct ThrowOnCopy 148 149 bool ThrowOnCopy::is_active = false; 150 151 #endif 152 153 namespace std { 154 template <typename T> 155 struct hash<std::reference_wrapper<T>> { 156 std::size_t operator()( const std::reference_wrapper<T>& wr ) const { 157 using type = typename std::remove_const<typename std::remove_const<T>::type>::type; 158 return std::hash<type>()(wr.get()); 159 } 160 }; 161 162 template <typename T> 163 struct hash<std::weak_ptr<T>> { 164 std::size_t operator()( const std::weak_ptr<T>& wr ) const { 165 return std::hash<T>()(*wr.lock().get()); 166 } 167 }; 168 169 #if TBB_USE_EXCEPTIONS 170 template <> 171 struct hash<ThrowOnCopy> { 172 std::size_t operator()( const ThrowOnCopy& ) const { 173 return 1; 174 } 175 }; 176 #endif 177 178 template <typename T> 179 struct equal_to<std::weak_ptr<T>> { 180 std::size_t operator()( const std::weak_ptr<T>& rhs, const std::weak_ptr<T>& lhs ) const { 181 return *rhs.lock().get() == *lhs.lock().get(); 182 } 183 }; 184 185 } // namespace std 186 187 #endif // __TBB_test_common_containers_common_H 188