1 /* 2 Copyright (c) 2005-2020 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 #include "oneapi/tbb/concurrent_unordered_map.h" 18 #include <common/test.h> 19 #include <common/utils.h> 20 #include <common/concurrent_unordered_common.h> 21 #include <memory> 22 #include <type_traits> 23 24 //! \file conformance_concurrent_unordered_map.cpp 25 //! \brief Test for [containers.concurrent_unordered_map containers.concurrent_unordered_multimap] specifications 26 27 template <typename... Args> 28 struct AllowMultimapping<oneapi::tbb::concurrent_unordered_multimap<Args...>> : std::true_type {}; 29 30 template <typename Key, typename Mapped> 31 using Allocator = LocalCountingAllocator<std::allocator<std::pair<const Key, Mapped>>>; 32 33 using map_type = oneapi::tbb::concurrent_unordered_map<int, int, std::hash<int>, std::equal_to<int>, Allocator<int, int>>; 34 using multimap_type = oneapi::tbb::concurrent_unordered_multimap<int, int, std::hash<int>, std::equal_to<int>, Allocator<int, int>>; 35 36 template <> 37 struct SpecialTests<map_type> { 38 static void Test() { 39 SpecialMapTests<map_type>(); 40 } 41 }; 42 43 template <> 44 struct SpecialTests<multimap_type> { 45 static void Test() { 46 SpecialMultiMapTests<multimap_type>(); 47 } 48 }; 49 50 template <template <typename... > class ContainerType> 51 void test_member_types() { 52 using default_container_type = ContainerType<int, int>; 53 static_assert(std::is_same<typename default_container_type::hasher, std::hash<int>>::value, 54 "Incorrect default template hasher"); 55 static_assert(std::is_same<typename default_container_type::key_equal, std::equal_to<int>>::value, 56 "Incorrect default template key equality"); 57 static_assert(std::is_same<typename default_container_type::allocator_type, 58 oneapi::tbb::tbb_allocator<std::pair<const int, int>>>::value, 59 "Incorrect default template allocator"); 60 61 auto test_hasher = [](const int&)->std::size_t { return 0; }; 62 auto test_equality = [](const int&, const int&)->bool { return true; }; 63 using test_allocator_type = std::allocator<std::pair<const int, int>>; 64 65 using container_type = ContainerType<int, int, decltype(test_hasher), 66 decltype(test_equality), test_allocator_type>; 67 68 static_assert(std::is_same<typename container_type::key_type, int>::value, 69 "Incorrect container key_type member type"); 70 static_assert(std::is_same<typename container_type::mapped_type, int>::value, 71 "Incorrect container mapped_type member type"); 72 static_assert(std::is_same<typename container_type::value_type, std::pair<const int, int>>::value, 73 "Incorrect container value_type member type"); 74 75 static_assert(std::is_unsigned<typename container_type::size_type>::value, 76 "Incorrect container size_type member type"); 77 static_assert(std::is_signed<typename container_type::difference_type>::value, 78 "Incorrect container difference_type member type"); 79 80 static_assert(std::is_same<typename container_type::hasher, decltype(test_hasher)>::value, 81 "Incorrect container hasher member type"); 82 static_assert(std::is_same<typename container_type::key_equal, decltype(test_equality)>::value, 83 "Incorrect container key_equal member type"); 84 85 using transparent_container_type = ContainerType<int, int, hasher_with_transparent_key_equal, 86 std::equal_to<int>, test_allocator_type>; 87 88 static_assert(std::is_same<typename transparent_container_type::key_equal, transparent_key_equality>::value, 89 "Incorrect container key_equal member type"); 90 static_assert(std::is_same<typename container_type::allocator_type, test_allocator_type>::value, 91 "Incorrect container allocator_type member type"); 92 93 using value_type = typename container_type::value_type; 94 static_assert(std::is_same<typename container_type::reference, value_type&>::value, 95 "Incorrect container reference member type"); 96 static_assert(std::is_same<typename container_type::const_reference, const value_type&>::value, 97 "Incorrect container const_reference member type"); 98 using allocator_type = typename container_type::allocator_type; 99 static_assert(std::is_same<typename container_type::pointer, typename std::allocator_traits<allocator_type>::pointer>::value, 100 "Incorrect container pointer member type"); 101 static_assert(std::is_same<typename container_type::const_pointer, typename std::allocator_traits<allocator_type>::const_pointer>::value, 102 "Incorrect container const_pointer member type"); 103 104 static_assert(utils::is_forward_iterator<typename container_type::iterator>::value, 105 "Incorrect container iterator member type"); 106 static_assert(!std::is_const<typename container_type::iterator::value_type>::value, 107 "Incorrect container iterator member type"); 108 static_assert(utils::is_forward_iterator<typename container_type::const_iterator>::value, 109 "Incorrect container const_iterator member type"); 110 static_assert(std::is_const<typename container_type::const_iterator::value_type>::value, 111 "Incorrect container iterator member type"); 112 static_assert(utils::is_forward_iterator<typename container_type::local_iterator>::value, 113 "Incorrect container local_iterator member type"); 114 static_assert(!std::is_const<typename container_type::local_iterator::value_type>::value, 115 "Incorrect container local_iterator member type"); 116 static_assert(utils::is_forward_iterator<typename container_type::const_local_iterator>::value, 117 "Incorrect container const_local_iterator member type"); 118 static_assert(std::is_const<typename container_type::const_local_iterator::value_type>::value, 119 "Incorrect container const_local_iterator member type"); 120 } 121 122 #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT 123 template <template <typename...> typename TMap> 124 void test_deduction_guides() { 125 using ComplexType = std::pair<int, std::string>; 126 using ComplexTypeConst = std::pair<const int, std::string>; 127 std::vector<ComplexType> v; 128 auto l = { ComplexTypeConst(1, "one"), ComplexTypeConst(2, "two")}; 129 using custom_allocator_type = std::allocator<ComplexTypeConst>; 130 131 // check TMap(InputIterator, InputIterator) 132 TMap m0(v.begin(), v.end()); 133 static_assert(std::is_same<decltype(m0), TMap<int, std::string>>::value); 134 135 // check TMap(InputIterator, InputIterator, size_t) 136 TMap m1(v.begin(), v.end(), 1); 137 static_assert(std::is_same<decltype(m1), TMap<int, std::string>>::value); 138 139 // check TMap(InputIterator, InputIterator, size_t, Hasher) 140 TMap m2(v.begin(), v.end(), 4, degenerate_hash<int>()); 141 static_assert(std::is_same<decltype(m2), TMap<int, std::string, degenerate_hash<int>>>::value); 142 143 // check TMap(InputIterator, InputIterator, size_t, Hasher, Equality) 144 TMap m3(v.begin(), v.end(), 4, degenerate_hash<int>(), std::less<int>()); 145 static_assert(std::is_same<decltype(m3), TMap<int, std::string, degenerate_hash<int>, std::less<int>>>::value); 146 147 // check TMap(InputIterator, InputIterator, size_t, Hasher, Equality, Allocator) 148 TMap m4(v.begin(), v.end(), 4, degenerate_hash<int>(), std::less<int>(), custom_allocator_type{}); 149 static_assert(std::is_same<decltype(m4), TMap<int, std::string, degenerate_hash<int>, 150 std::less<int>, custom_allocator_type>>::value); 151 152 // check TMap(InputIterator, InputIterator, size_t, Allocator) 153 TMap m5(v.begin(), v.end(), 5, custom_allocator_type{}); 154 static_assert(std::is_same<decltype(m5), TMap<int, std::string, std::hash<int>, 155 std::equal_to<int>, custom_allocator_type>>::value); 156 157 // check TMap(InputIterator, InputIterator, size_t, Hasher, Allocator) 158 TMap m6(v.begin(), v.end(), 4, degenerate_hash<int>(), custom_allocator_type{}); 159 static_assert(std::is_same<decltype(m6), TMap<int, std::string, degenerate_hash<int>, 160 std::equal_to<int>, custom_allocator_type>>::value); 161 162 // check TMap(std::initializer_list) 163 TMap m7(l); 164 static_assert(std::is_same<decltype(m7), TMap<int, std::string>>::value); 165 166 // check TMap(std::initializer_list, size_t) 167 TMap m8(l, 1); 168 static_assert(std::is_same<decltype(m8), TMap<int, std::string>>::value); 169 170 // check TMap(std::initializer_list, size_t, Hasher) 171 TMap m9(l, 4, degenerate_hash<int>()); 172 static_assert(std::is_same<decltype(m9), TMap<int, std::string, degenerate_hash<int>>>::value); 173 174 // check TMap(std::initializer_list, size_t, Hasher, Equality) 175 TMap m10(l, 4, degenerate_hash<int>(), std::less<int>()); 176 static_assert(std::is_same<decltype(m10), TMap<int, std::string, degenerate_hash<int>, std::less<int>>>::value); 177 178 // check TMap(std::initializer_list, size_t, Hasher, Equality, Allocator) 179 TMap m11(l, 4, degenerate_hash<int>(), std::less<int>(), custom_allocator_type{}); 180 static_assert(std::is_same<decltype(m11), TMap<int, std::string, degenerate_hash<int>, 181 std::less<int>, custom_allocator_type>>::value); 182 183 // check TMap(std::initializer_list, size_t, Allocator) 184 TMap m12(l, 4, custom_allocator_type{}); 185 static_assert(std::is_same<decltype(m12), TMap<int, std::string, std::hash<int>, 186 std::equal_to<int>, custom_allocator_type>>::value); 187 188 // check TMap(std::initializer_list, size_t, Hasher, Allocator) 189 TMap m13(l, 4, degenerate_hash<int>(), custom_allocator_type{}); 190 static_assert(std::is_same<decltype(m13), TMap<int, std::string, degenerate_hash<int>, 191 std::equal_to<int>, custom_allocator_type>>::value); 192 193 // check TMap(TMap &) 194 TMap m14(m1); 195 static_assert(std::is_same<decltype(m14), decltype(m1)>::value); 196 197 // check TMap(TMap &, Allocator) 198 // TODO: investigate why no implicit deduction guides generated for this ctor 199 TMap m15(m5, custom_allocator_type{}); 200 static_assert(std::is_same<decltype(m15), decltype(m5)>::value); 201 202 // check TMap(TMap &&) 203 TMap m16(std::move(m1)); 204 static_assert(std::is_same<decltype(m16), decltype(m1)>::value); 205 206 // check TMap(TMap &&, Allocator) 207 // TODO: investigate why no implicit deduction guides generated for this ctor 208 TMap m17(std::move(m5), custom_allocator_type{}); 209 static_assert(std::is_same<decltype(m17), decltype(m5)>::value); 210 } 211 #endif 212 213 void test_heterogeneous_functions() { 214 check_heterogeneous_functions_key_int<oneapi::tbb::concurrent_unordered_map, int, int>(); 215 check_heterogeneous_functions_key_int<oneapi::tbb::concurrent_unordered_multimap, int, int>(); 216 check_heterogeneous_functions_key_string<oneapi::tbb::concurrent_unordered_map, std::string, std::string>(); 217 check_heterogeneous_functions_key_string<oneapi::tbb::concurrent_unordered_multimap, std::string, std::string>(); 218 } 219 220 struct CumapTraits : UnorderedMoveTraitsBase { 221 template <typename T, typename Allocator> 222 using container_type = oneapi::tbb::concurrent_unordered_map<T, T, std::hash<T>, std::equal_to<T>, Allocator>; 223 224 template <typename T> 225 using container_value_type = std::pair<const T, T>; 226 227 using init_iterator_type = move_support_tests::FooPairIterator; 228 }; // struct CumapTraits 229 230 struct CumultimapTraits : UnorderedMoveTraitsBase { 231 template <typename T, typename Allocator> 232 using container_type = oneapi::tbb::concurrent_unordered_multimap<T, T, std::hash<T>, std::equal_to<T>, Allocator>; 233 234 template <typename T> 235 using container_value_type = std::pair<const T, T>; 236 237 using init_iterator_type = move_support_tests::FooPairIterator; 238 }; // struct CumultimapTraits 239 240 //! Testing concurrent_unordered_map member types 241 //! \brief \ref interface \ref requirement 242 TEST_CASE("concurrent_unordered_map member types") { 243 test_member_types<oneapi::tbb::concurrent_unordered_map>(); 244 } 245 246 //! Testing requirements of concurrent_unordered_map 247 //! \brief \ref interface \ref requirement 248 TEST_CASE("concurrent_unordered_map requirements") { 249 test_basic<map_type>(); 250 } 251 252 //! Testing multithreading support in concurrent_unordered_map 253 //! \brief \ref requirement 254 TEST_CASE("concurrent_unordered_map multithreading support") { 255 test_concurrent<map_type>(); 256 } 257 258 //! Testing move constructors and assignment operator in concurrent_unordered_map 259 //! \brief \ref interface \ref requirement 260 TEST_CASE("concurrent_unordered_map move semantics support") { 261 test_rvalue_ref_support<CumapTraits>(); 262 } 263 264 //! Testing std::initializer_list constructors and modifiers in concurrent_unordered_map 265 //! \brief \ref interface \ref requirement 266 TEST_CASE("std::initializer_list support in concurrent_unordered_map") { 267 test_initializer_list_support<map_type>({{1, 1}, {2, 2}, {3, 3}, {4, 4}}); 268 } 269 270 //! Testing node handling in concurrent_unordered_map 271 //! \brief \ref interface \ref requirement 272 TEST_CASE("node handling support in concurrent_unordered_map") { 273 node_handling_tests::test_node_handling_support<map_type>(); 274 } 275 276 //! Testing std::allocator_traits support in concurrent_unordered_map 277 //! \brief \ref interface \ref requirement 278 TEST_CASE("std::allocator_traits support in concurrent_unordered_map") { 279 test_allocator_traits_support<CumapTraits>(); 280 } 281 282 //! Testing heterogeneous overloads in concurrent_unordered_map 283 //! \brief \ref interface \ref requirement 284 TEST_CASE("heterogeneous overloads in concurrent_unordered_map") { 285 check_heterogeneous_functions_key_int<oneapi::tbb::concurrent_unordered_map, int, int>(); 286 check_heterogeneous_functions_key_string<oneapi::tbb::concurrent_unordered_map, std::string, std::string>(); 287 } 288 289 //! Testing insert overloads with generic pair in concurrent_unordered_map 290 //! \brief \ref interface \ref requirement 291 TEST_CASE("insertion by generic pair in concurrent_unordered_map") { 292 test_insert_by_generic_pair<oneapi::tbb::concurrent_unordered_map>(); 293 } 294 295 #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT 296 //! Testing Class Template Argument Deduction in concurrent_unordered_map 297 //! \brief \ref interface \ref requirement 298 TEST_CASE("CTAD support in concurrent_unordered_map") { 299 test_deduction_guides<oneapi::tbb::concurrent_unordered_map>(); 300 } 301 #endif 302 303 //! Testing concurrent_unordered_multimap member types 304 //! \brief \ref interface \ref requirement 305 TEST_CASE("concurrent_unordered_multimap member types") { 306 test_member_types<oneapi::tbb::concurrent_unordered_multimap>(); 307 } 308 309 //! Testing requirements of concurrent_unordered_multimap 310 //! \brief \ref interface \ref requirement 311 TEST_CASE("concurrent_unordered_multimap requirements") { 312 test_basic<multimap_type>(); 313 } 314 315 //! Testing multithreading support in concurrent_unordered_multimap 316 //! \brief \ref requirement 317 TEST_CASE("concurrent_unordered_multimap multithreading support") { 318 test_concurrent<multimap_type>(); 319 } 320 321 //! Testing move constructors and assignment operator in concurrent_unordered_multimap 322 //! \brief \ref interface \ref requirement 323 TEST_CASE("concurrent_unordered_multimap move semantics support") { 324 test_rvalue_ref_support<CumultimapTraits>(); 325 } 326 327 //! Testing std::initializer_list constructors and modifiers in concurrent_unordered_multimap 328 //! \brief \ref interface \ref requirement 329 TEST_CASE("std::initializer_list support in concurrent_unordered_multimap") { 330 test_initializer_list_support<multimap_type>({{1, 1}, {2, 2}, {3, 3}, {4, 4}, {4, 40}}); 331 } 332 333 //! Testing node handling support in concurrent_unordered_multimap 334 //! \brief \ref interface \ref requirement 335 TEST_CASE("node handling support in concurrent_unordered_multimap") { 336 node_handling_tests::test_node_handling_support<multimap_type>(); 337 } 338 339 //! Testing std::allocator_traits support in concurrent_unordered_multimap 340 //! \brief \ref interface \ref requirement 341 TEST_CASE("std::allocator_traits support in concurrent_unordered_multimap") { 342 test_allocator_traits_support<CumultimapTraits>(); 343 } 344 345 //! Testing heterogeneous overloads in concurrent_unordered_multimap 346 //! \brief \ref interface \ref requirement 347 TEST_CASE("heterogeneous overloads in concurrent_unordered_multimap") { 348 check_heterogeneous_functions_key_int<oneapi::tbb::concurrent_unordered_multimap, int, int>(); 349 check_heterogeneous_functions_key_string<oneapi::tbb::concurrent_unordered_multimap, std::string, std::string>(); 350 } 351 352 //! Testing insert overloads with generic pair in concurrent_unordered_multimap 353 //! \brief \ref interface \ref requirement 354 TEST_CASE("insertion by generic pair in concurrent_unordered_multimap") { 355 test_insert_by_generic_pair<oneapi::tbb::concurrent_unordered_multimap>(); 356 } 357 358 #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT 359 //! Testing Class Template Argument Deduction in concurrent_unordered_multimap 360 //! \brief \ref interface \ref requirement 361 TEST_CASE("CTAD support in concurrent_unordered_multimap") { 362 test_deduction_guides<oneapi::tbb::concurrent_unordered_multimap>(); 363 } 364 #endif 365 366 //! Testing of merge operations in concurrent_unordered_map and concurrent_unordered_multimap 367 //! \brief \ref interface \ref requirement 368 TEST_CASE("merge operations") { 369 node_handling_tests::test_merge<map_type, multimap_type>(1000); 370 } 371