insert_exception_tests.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416
  1. // Copyright 2006-2009 Daniel James.
  2. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  3. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  4. #include "./containers.hpp"
  5. #include "../helpers/helpers.hpp"
  6. #include "../helpers/invariants.hpp"
  7. #include "../helpers/random_values.hpp"
  8. #include "../helpers/strong.hpp"
  9. #include "../helpers/tracker.hpp"
  10. #include <cmath>
  11. #include <string>
  12. test::seed_t initialize_seed(747373);
  13. // Fill in a container so that it's about to rehash
  14. template <typename T> void rehash_prep(T& x)
  15. {
  16. using namespace std;
  17. typedef typename T::size_type size_type;
  18. x.max_load_factor(0.25);
  19. size_type bucket_count = x.bucket_count();
  20. size_type initial_elements = static_cast<size_type>(
  21. ceil((double)bucket_count * (double)x.max_load_factor()) - 1);
  22. test::random_values<T> v(initial_elements);
  23. x.insert(v.begin(), v.end());
  24. BOOST_TEST(bucket_count == x.bucket_count());
  25. }
  26. // Overload to generate inserters that need type information.
  27. template <typename Inserter, typename T>
  28. Inserter generate(Inserter inserter, T&)
  29. {
  30. return inserter;
  31. }
  32. // Get the iterator returned from an insert/emplace.
  33. template <typename T> T get_iterator(T const& x) { return x; }
  34. template <typename T> T get_iterator(std::pair<T, bool> const& x)
  35. {
  36. return x.first;
  37. }
  38. // Generic insert exception test for typical single element inserts..
  39. template <typename T, typename Inserter, typename Values>
  40. void insert_exception_test_impl(T x, Inserter insert, Values const& v)
  41. {
  42. test::strong<T> strong;
  43. test::ordered<T> tracker;
  44. tracker.insert(x.begin(), x.end());
  45. try {
  46. ENABLE_EXCEPTIONS;
  47. for (typename Values::const_iterator it = v.begin(); it != v.end(); ++it) {
  48. strong.store(x, test::detail::tracker.count_allocations);
  49. insert(x, it);
  50. }
  51. } catch (...) {
  52. test::check_equivalent_keys(x);
  53. insert.exception_check(x, strong);
  54. throw;
  55. }
  56. test::check_equivalent_keys(x);
  57. insert.track(tracker, v.begin(), v.end());
  58. tracker.compare(x);
  59. }
  60. // Simple insert exception test
  61. template <typename T, typename Inserter>
  62. void insert_exception_test(T*, Inserter insert, test::random_generator gen)
  63. {
  64. for (int i = 0; i < 5; ++i) {
  65. test::random_values<T> v(10, gen);
  66. T x;
  67. EXCEPTION_LOOP(insert_exception_test_impl(x, generate(insert, x), v));
  68. }
  69. }
  70. // Insert into a container which is about to hit its max load, so that it
  71. // rehashes.
  72. template <typename T, typename Inserter>
  73. void insert_rehash_exception_test(
  74. T*, Inserter insert, test::random_generator gen)
  75. {
  76. for (int i = 0; i < 5; ++i) {
  77. T x;
  78. rehash_prep(x);
  79. test::random_values<T> v2(5, gen);
  80. EXCEPTION_LOOP(insert_exception_test_impl(x, generate(insert, x), v2));
  81. }
  82. }
  83. // Various methods for inserting a single element
  84. struct inserter_base
  85. {
  86. template <typename T> void exception_check(T& x, test::strong<T>& strong)
  87. {
  88. std::string scope(test::scope);
  89. if (scope.find("hash::operator()") == std::string::npos)
  90. strong.test(x, test::detail::tracker.count_allocations);
  91. }
  92. template <typename T, typename Iterator>
  93. void track(T& tracker, Iterator begin, Iterator end)
  94. {
  95. tracker.insert(begin, end);
  96. }
  97. };
  98. struct insert_lvalue_type : inserter_base
  99. {
  100. template <typename T, typename Iterator> void operator()(T& x, Iterator it)
  101. {
  102. x.insert(*it);
  103. }
  104. } insert_lvalue;
  105. struct insert_lvalue_begin_type : inserter_base
  106. {
  107. template <typename T, typename Iterator> void operator()(T& x, Iterator it)
  108. {
  109. x.insert(x.begin(), *it);
  110. }
  111. } insert_lvalue_begin;
  112. struct insert_lvalue_end_type : inserter_base
  113. {
  114. template <typename T, typename Iterator> void operator()(T& x, Iterator it)
  115. {
  116. x.insert(x.end(), *it);
  117. }
  118. } insert_lvalue_end;
  119. template <typename T> struct insert_lvalue_pos_type_impl : inserter_base
  120. {
  121. typename T::iterator pos;
  122. insert_lvalue_pos_type_impl(T& x) : pos(x.begin()) {}
  123. template <typename Iterator> void operator()(T& x, Iterator it)
  124. {
  125. pos = get_iterator(x.insert(pos, *it));
  126. }
  127. };
  128. struct insert_lvalue_pos_type
  129. {
  130. template <typename T>
  131. friend insert_lvalue_pos_type_impl<T> generate(insert_lvalue_pos_type, T& x)
  132. {
  133. return insert_lvalue_pos_type_impl<T>(x);
  134. }
  135. } insert_lvalue_pos;
  136. struct insert_single_item_range_type : inserter_base
  137. {
  138. template <typename T, typename Iterator> void operator()(T& x, Iterator it)
  139. {
  140. x.insert(it, test::next(it));
  141. }
  142. } insert_single_item_range;
  143. struct emplace_lvalue_type : inserter_base
  144. {
  145. template <typename T, typename Iterator> void operator()(T& x, Iterator it)
  146. {
  147. x.emplace(*it);
  148. }
  149. } emplace_lvalue;
  150. struct emplace_lvalue_begin_type : inserter_base
  151. {
  152. template <typename T, typename Iterator> void operator()(T& x, Iterator it)
  153. {
  154. x.emplace_hint(x.begin(), *it);
  155. }
  156. } emplace_lvalue_begin;
  157. struct emplace_lvalue_end_type : inserter_base
  158. {
  159. template <typename T, typename Iterator> void operator()(T& x, Iterator it)
  160. {
  161. x.emplace_hint(x.end(), *it);
  162. }
  163. } emplace_lvalue_end;
  164. template <typename T> struct emplace_lvalue_pos_type_impl : inserter_base
  165. {
  166. typename T::iterator pos;
  167. emplace_lvalue_pos_type_impl(T& x) : pos(x.begin()) {}
  168. template <typename Iterator> void operator()(T& x, Iterator it)
  169. {
  170. pos = get_iterator(x.emplace_hint(pos, *it));
  171. }
  172. };
  173. struct emplace_lvalue_pos_type
  174. {
  175. template <typename T>
  176. friend emplace_lvalue_pos_type_impl<T> generate(emplace_lvalue_pos_type, T& x)
  177. {
  178. return emplace_lvalue_pos_type_impl<T>(x);
  179. }
  180. } emplace_lvalue_pos;
  181. // Run the exception tests in various combinations.
  182. test_set* test_set_;
  183. test_multiset* test_multiset_;
  184. test_map* test_map_;
  185. test_multimap* test_multimap_;
  186. using test::default_generator;
  187. using test::limited_range;
  188. using test::generate_collisions;
  189. // clang-format off
  190. UNORDERED_TEST(insert_exception_test,
  191. ((test_set_)(test_multiset_)(test_map_)(test_multimap_))
  192. ((insert_lvalue)(insert_lvalue_begin)(insert_lvalue_end)
  193. (insert_lvalue_pos)(insert_single_item_range)
  194. (emplace_lvalue)(emplace_lvalue_begin)(emplace_lvalue_end)
  195. (emplace_lvalue_pos)
  196. )
  197. ((default_generator)(limited_range)(generate_collisions))
  198. )
  199. UNORDERED_TEST(insert_rehash_exception_test,
  200. ((test_set_)(test_multiset_)(test_map_)(test_multimap_))
  201. ((insert_lvalue)(insert_lvalue_begin)(insert_lvalue_end)
  202. (insert_lvalue_pos)(insert_single_item_range)
  203. (emplace_lvalue)(emplace_lvalue_begin)(emplace_lvalue_end)
  204. (emplace_lvalue_pos)
  205. )
  206. ((default_generator)(limited_range)(generate_collisions))
  207. )
  208. // clang-format on
  209. // Repeat insert tests with pairs
  210. struct pair_emplace_type : inserter_base
  211. {
  212. template <typename T, typename Iterator> void operator()(T& x, Iterator it)
  213. {
  214. x.emplace(boost::unordered::piecewise_construct,
  215. boost::make_tuple(it->first), boost::make_tuple(it->second));
  216. }
  217. } pair_emplace;
  218. struct pair_emplace2_type : inserter_base
  219. {
  220. template <typename T, typename Iterator> void operator()(T& x, Iterator it)
  221. {
  222. x.emplace_hint(x.begin(), boost::unordered::piecewise_construct,
  223. boost::make_tuple(it->first),
  224. boost::make_tuple(it->second.tag1_, it->second.tag2_));
  225. }
  226. } pair_emplace2;
  227. test_pair_set* test_pair_set_;
  228. test_pair_multiset* test_pair_multiset_;
  229. // clang-format off
  230. UNORDERED_TEST(insert_exception_test,
  231. ((test_pair_set_)(test_pair_multiset_)(test_map_)(test_multimap_))
  232. ((pair_emplace)(pair_emplace2))
  233. ((default_generator)(limited_range)(generate_collisions))
  234. )
  235. UNORDERED_TEST(insert_rehash_exception_test,
  236. ((test_pair_set_)(test_pair_multiset_)(test_map_)(test_multimap_))
  237. ((pair_emplace)(pair_emplace2))
  238. ((default_generator)(limited_range)(generate_collisions))
  239. )
  240. // clang-format on
  241. // Test inserting using operator[]
  242. struct try_emplace_type : inserter_base
  243. {
  244. template <typename T, typename Iterator> void operator()(T& x, Iterator it)
  245. {
  246. x.try_emplace(it->first, it->second);
  247. }
  248. } try_emplace;
  249. struct try_emplace2_type : inserter_base
  250. {
  251. template <typename T, typename Iterator> void operator()(T& x, Iterator it)
  252. {
  253. x.try_emplace(it->first, it->second.tag1_, it->second.tag2_);
  254. }
  255. } try_emplace2;
  256. struct map_inserter_base
  257. {
  258. template <typename T> void exception_check(T& x, test::strong<T>& strong)
  259. {
  260. std::string scope(test::scope);
  261. if (scope.find("hash::operator()") == std::string::npos &&
  262. scope.find("::operator=") == std::string::npos)
  263. strong.test(x, test::detail::tracker.count_allocations);
  264. }
  265. template <typename T, typename Iterator>
  266. void track(T& tracker, Iterator begin, Iterator end)
  267. {
  268. for (; begin != end; ++begin) {
  269. tracker[begin->first] = begin->second;
  270. }
  271. }
  272. };
  273. struct map_insert_operator_type : map_inserter_base
  274. {
  275. template <typename T, typename Iterator> void operator()(T& x, Iterator it)
  276. {
  277. x[it->first] = it->second;
  278. }
  279. } map_insert_operator;
  280. struct map_insert_or_assign_type : map_inserter_base
  281. {
  282. template <typename T, typename Iterator> void operator()(T& x, Iterator it)
  283. {
  284. x.insert_or_assign(it->first, it->second);
  285. }
  286. } map_insert_or_assign;
  287. // clang-format off
  288. UNORDERED_TEST(insert_exception_test,
  289. ((test_map_))
  290. ((try_emplace)(try_emplace2)(map_insert_operator)(map_insert_or_assign))
  291. ((default_generator)(limited_range)(generate_collisions))
  292. )
  293. UNORDERED_TEST(insert_rehash_exception_test,
  294. ((test_map_))
  295. ((try_emplace)(try_emplace2)(map_insert_operator)(map_insert_or_assign))
  296. ((default_generator)(limited_range)(generate_collisions))
  297. )
  298. // clang-format on
  299. // Range insert tests
  300. template <typename T, typename Values>
  301. void insert_range_exception_test_impl(T x, Values const& v)
  302. {
  303. test::ordered<T> tracker;
  304. tracker.insert(x.begin(), x.end());
  305. try {
  306. ENABLE_EXCEPTIONS;
  307. x.insert(v.begin(), v.end());
  308. } catch (...) {
  309. test::check_equivalent_keys(x);
  310. throw;
  311. }
  312. test::check_equivalent_keys(x);
  313. tracker.insert(v.begin(), v.end());
  314. tracker.compare(x);
  315. }
  316. template <typename T>
  317. void insert_range_exception_test(T*, test::random_generator gen)
  318. {
  319. for (int i = 0; i < 5; ++i) {
  320. test::random_values<T> v(10, gen);
  321. T x;
  322. EXCEPTION_LOOP(insert_range_exception_test_impl(x, v));
  323. }
  324. }
  325. template <typename T>
  326. void insert_range_rehash_exception_test(T*, test::random_generator gen)
  327. {
  328. for (int i = 0; i < 5; ++i) {
  329. T x;
  330. rehash_prep(x);
  331. test::random_values<T> v2(5, gen);
  332. EXCEPTION_LOOP(insert_range_exception_test_impl(x, v2));
  333. }
  334. }
  335. // clang-format off
  336. UNORDERED_TEST(insert_range_exception_test,
  337. ((test_set_)(test_multiset_)(test_map_)(test_multimap_))
  338. ((default_generator)(limited_range)(generate_collisions))
  339. )
  340. UNORDERED_TEST(insert_range_rehash_exception_test,
  341. ((test_set_)(test_multiset_)(test_map_)(test_multimap_))
  342. ((default_generator)(limited_range)(generate_collisions))
  343. )
  344. // clang-format on
  345. RUN_TESTS()