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>
test_allocator_traits()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