unordered_test.hpp 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751
  1. /////////////////////////////////////////////////////////////////////////////
  2. //
  3. // (C) Copyright Ion Gaztanaga 2015-2015.
  4. //
  5. // Distributed under the Boost Software License, Version 1.0.
  6. // (See accompanying file LICENSE_1_0.txt or copy at
  7. // http://www.boost.org/LICENSE_1_0.txt)
  8. //
  9. // See http://www.boost.org/libs/intrusive for documentation.
  10. //
  11. /////////////////////////////////////////////////////////////////////////////
  12. #include <boost/intrusive/pointer_traits.hpp>
  13. #include <boost/intrusive/detail/iterator.hpp>
  14. #include "common_functors.hpp"
  15. #include <vector>
  16. #include <algorithm> //std::sort
  17. #include <set>
  18. #include <boost/detail/lightweight_test.hpp>
  19. #include "test_macros.hpp"
  20. #include "test_container.hpp"
  21. #include "unordered_test_common.hpp"
  22. namespace boost{
  23. namespace intrusive{
  24. namespace test{
  25. static const std::size_t BucketSize = 8;
  26. template<class ContainerDefiner>
  27. struct test_unordered
  28. {
  29. typedef typename ContainerDefiner::value_cont_type value_cont_type;
  30. static void test_all(value_cont_type& values);
  31. private:
  32. static void test_sort(value_cont_type& values);
  33. static void test_insert(value_cont_type& values, detail::true_);
  34. static void test_insert(value_cont_type& values, detail::false_);
  35. static void test_swap(value_cont_type& values);
  36. static void test_rehash(value_cont_type& values, detail::true_);
  37. static void test_rehash(value_cont_type& values, detail::false_);
  38. static void test_find(value_cont_type& values);
  39. static void test_impl();
  40. static void test_clone(value_cont_type& values);
  41. };
  42. template<class ContainerDefiner>
  43. void test_unordered<ContainerDefiner>::test_all (value_cont_type& values)
  44. {
  45. typedef typename ContainerDefiner::template container
  46. <>::type unordered_type;
  47. typedef typename unordered_type::bucket_traits bucket_traits;
  48. typedef typename unordered_type::bucket_ptr bucket_ptr;
  49. {
  50. typename unordered_type::bucket_type buckets [BucketSize];
  51. unordered_type testset
  52. (bucket_traits(pointer_traits<bucket_ptr>::pointer_to(buckets[0]), BucketSize));
  53. testset.insert(values.begin(), values.end());
  54. test::test_container(testset);
  55. testset.clear();
  56. testset.insert(values.begin(), values.end());
  57. test::test_common_unordered_and_associative_container(testset, values);
  58. testset.clear();
  59. testset.insert(values.begin(), values.end());
  60. test::test_unordered_associative_container(testset, values);
  61. testset.clear();
  62. testset.insert(values.begin(), values.end());
  63. typedef detail::bool_<boost::intrusive::test::is_multikey_true
  64. <unordered_type>::value> select_t;
  65. test::test_maybe_unique_container(testset, values, select_t());
  66. }
  67. {
  68. value_cont_type vals(BucketSize);
  69. for (int i = 0; i < (int)BucketSize; ++i)
  70. (&vals[i])->value_ = i;
  71. typename unordered_type::bucket_type buckets [BucketSize];
  72. unordered_type testset(bucket_traits(
  73. pointer_traits<bucket_ptr>::pointer_to(buckets[0]), BucketSize));
  74. testset.insert(vals.begin(), vals.end());
  75. test::test_iterator_forward(testset);
  76. }
  77. test_sort(values);
  78. test_insert(values, detail::bool_<boost::intrusive::test::is_multikey_true<unordered_type>::value>());
  79. test_swap(values);
  80. test_rehash(values, detail::bool_<unordered_type::incremental>());
  81. test_find(values);
  82. test_impl();
  83. test_clone(values);
  84. }
  85. //test case due to an error in tree implementation:
  86. template<class ContainerDefiner>
  87. void test_unordered<ContainerDefiner>::test_impl()
  88. {
  89. typedef typename ContainerDefiner::template container
  90. <>::type unordered_type;
  91. typedef typename unordered_type::bucket_traits bucket_traits;
  92. typedef typename unordered_type::bucket_ptr bucket_ptr;
  93. value_cont_type values (5);
  94. for (int i = 0; i < 5; ++i)
  95. values[i].value_ = i;
  96. typename unordered_type::bucket_type buckets [BucketSize];
  97. unordered_type testset(bucket_traits(
  98. pointer_traits<bucket_ptr>::pointer_to(buckets[0]), BucketSize));
  99. for (int i = 0; i < 5; ++i)
  100. testset.insert (values[i]);
  101. testset.erase (testset.iterator_to (values[0]));
  102. testset.erase (testset.iterator_to (values[1]));
  103. testset.insert (values[1]);
  104. testset.erase (testset.iterator_to (values[2]));
  105. testset.erase (testset.iterator_to (values[3]));
  106. }
  107. //test: constructor, iterator, clear, reverse_iterator, front, back, size:
  108. template<class ContainerDefiner>
  109. void test_unordered<ContainerDefiner>::test_sort(value_cont_type& values)
  110. {
  111. typedef typename ContainerDefiner::template container
  112. <>::type unordered_type;
  113. typedef typename unordered_type::bucket_traits bucket_traits;
  114. typedef typename unordered_type::bucket_ptr bucket_ptr;
  115. typename unordered_type::bucket_type buckets [BucketSize];
  116. unordered_type testset1
  117. (values.begin(), values.end(), bucket_traits
  118. (pointer_traits<bucket_ptr>::pointer_to(buckets[0]), BucketSize));
  119. if(unordered_type::incremental){
  120. { int init_values [] = { 4, 5, 1, 2, 2, 3 };
  121. TEST_INTRUSIVE_SEQUENCE_MAYBEUNIQUE( init_values, testset1 ); }
  122. }
  123. else{
  124. { int init_values [] = { 1, 2, 2, 3, 4, 5 };
  125. TEST_INTRUSIVE_SEQUENCE_MAYBEUNIQUE( init_values, testset1 ); }
  126. }
  127. testset1.clear();
  128. BOOST_TEST (testset1.empty());
  129. }
  130. //test: insert, const_iterator, const_reverse_iterator, erase, iterator_to:
  131. template<class ContainerDefiner>
  132. void test_unordered<ContainerDefiner>::test_insert(value_cont_type& values, detail::false_) //not multikey
  133. {
  134. typedef typename ContainerDefiner::template container
  135. <>::type unordered_set_type;
  136. typedef typename unordered_set_type::bucket_traits bucket_traits;
  137. typedef typename unordered_set_type::key_of_value key_of_value;
  138. typename unordered_set_type::bucket_type buckets [BucketSize];
  139. unordered_set_type testset(bucket_traits(
  140. pointer_traits<typename unordered_set_type::bucket_ptr>::
  141. pointer_to(buckets[0]), BucketSize));
  142. testset.insert(&values[0] + 2, &values[0] + 5);
  143. typename unordered_set_type::insert_commit_data commit_data;
  144. BOOST_TEST ((!testset.insert_check(key_of_value()(values[2]), commit_data).second));
  145. BOOST_TEST (( testset.insert_check(key_of_value()(values[0]), commit_data).second));
  146. const unordered_set_type& const_testset = testset;
  147. if(unordered_set_type::incremental)
  148. {
  149. { int init_values [] = { 4, 5, 1 };
  150. TEST_INTRUSIVE_SEQUENCE_MAYBEUNIQUE( init_values, const_testset ); }
  151. typename unordered_set_type::iterator i = testset.begin();
  152. BOOST_TEST (i->value_ == 4);
  153. i = testset.insert(values[0]).first;
  154. BOOST_TEST (&*i == &values[0]);
  155. i = testset.iterator_to (values[2]);
  156. BOOST_TEST (&*i == &values[2]);
  157. testset.erase (i);
  158. { int init_values [] = { 5, 1, 3 };
  159. TEST_INTRUSIVE_SEQUENCE_MAYBEUNIQUE( init_values, const_testset ); }
  160. }
  161. else{
  162. { int init_values [] = { 1, 4, 5 };
  163. TEST_INTRUSIVE_SEQUENCE_MAYBEUNIQUE( init_values, const_testset ); }
  164. typename unordered_set_type::iterator i = testset.begin();
  165. BOOST_TEST (i->value_ == 1);
  166. i = testset.insert(values[0]).first;
  167. BOOST_TEST (&*i == &values[0]);
  168. i = testset.iterator_to (values[2]);
  169. BOOST_TEST (&*i == &values[2]);
  170. testset.erase (i);
  171. { int init_values [] = { 1, 3, 5 };
  172. TEST_INTRUSIVE_SEQUENCE_MAYBEUNIQUE( init_values, const_testset ); }
  173. }
  174. }
  175. template<class ContainerDefiner>
  176. void test_unordered<ContainerDefiner>::test_insert(value_cont_type& values, detail::true_) //is multikey
  177. {
  178. typedef typename ContainerDefiner::template container
  179. <>::type unordered_type;
  180. typedef typename unordered_type::bucket_traits bucket_traits;
  181. typedef typename unordered_type::bucket_ptr bucket_ptr;
  182. typedef typename unordered_type::iterator iterator;
  183. typedef typename unordered_type::key_type key_type;
  184. {
  185. typename unordered_type::bucket_type buckets [BucketSize];
  186. unordered_type testset(bucket_traits(
  187. pointer_traits<bucket_ptr>::pointer_to(buckets[0]), BucketSize));
  188. testset.insert(&values[0] + 2, &values[0] + 5);
  189. const unordered_type& const_testset = testset;
  190. if(unordered_type::incremental){
  191. {
  192. { int init_values [] = { 4, 5, 1 };
  193. TEST_INTRUSIVE_SEQUENCE_MAYBEUNIQUE( init_values, const_testset ); }
  194. typename unordered_type::iterator i = testset.begin();
  195. BOOST_TEST (i->value_ == 4);
  196. i = testset.insert (values[0]);
  197. BOOST_TEST (&*i == &values[0]);
  198. i = testset.iterator_to (values[2]);
  199. BOOST_TEST (&*i == &values[2]);
  200. testset.erase(i);
  201. { int init_values [] = { 5, 1, 3 };
  202. TEST_INTRUSIVE_SEQUENCE_MAYBEUNIQUE( init_values, const_testset ); }
  203. testset.clear();
  204. testset.insert(&values[0], &values[0] + values.size());
  205. { int init_values [] = { 4, 5, 1, 2, 2, 3 };
  206. TEST_INTRUSIVE_SEQUENCE_MAYBEUNIQUE( init_values, const_testset ); }
  207. BOOST_TEST (testset.erase(key_type(1)) == 1);
  208. BOOST_TEST (testset.erase(key_type(2)) == 2);
  209. BOOST_TEST (testset.erase(key_type(3)) == 1);
  210. BOOST_TEST (testset.erase(key_type(4)) == 1);
  211. BOOST_TEST (testset.erase(key_type(5)) == 1);
  212. BOOST_TEST (testset.empty() == true);
  213. //Now with a single bucket
  214. typename unordered_type::bucket_type single_bucket[1];
  215. unordered_type testset2(bucket_traits(
  216. pointer_traits<bucket_ptr>::pointer_to(single_bucket[0]), 1));
  217. testset2.insert(&values[0], &values[0] + values.size());
  218. BOOST_TEST (testset2.erase(key_type(5)) == 1);
  219. BOOST_TEST (testset2.erase(key_type(2)) == 2);
  220. BOOST_TEST (testset2.erase(key_type(1)) == 1);
  221. BOOST_TEST (testset2.erase(key_type(4)) == 1);
  222. BOOST_TEST (testset2.erase(key_type(3)) == 1);
  223. BOOST_TEST (testset2.empty() == true);
  224. }
  225. }
  226. else{
  227. {
  228. { int init_values [] = { 1, 4, 5 };
  229. TEST_INTRUSIVE_SEQUENCE_MAYBEUNIQUE( init_values, const_testset ); }
  230. typename unordered_type::iterator i = testset.begin();
  231. BOOST_TEST (i->value_ == 1);
  232. i = testset.insert (values[0]);
  233. BOOST_TEST (&*i == &values[0]);
  234. i = testset.iterator_to (values[2]);
  235. BOOST_TEST (&*i == &values[2]);
  236. testset.erase(i);
  237. { int init_values [] = { 1, 3, 5 };
  238. TEST_INTRUSIVE_SEQUENCE_MAYBEUNIQUE( init_values, const_testset ); }
  239. testset.clear();
  240. testset.insert(&values[0], &values[0] + values.size());
  241. { int init_values [] = { 1, 2, 2, 3, 4, 5 };
  242. TEST_INTRUSIVE_SEQUENCE_MAYBEUNIQUE( init_values, const_testset ); }
  243. BOOST_TEST (testset.erase(key_type(1)) == 1);
  244. BOOST_TEST (testset.erase(key_type(2)) == 2);
  245. BOOST_TEST (testset.erase(key_type(3)) == 1);
  246. BOOST_TEST (testset.erase(key_type(4)) == 1);
  247. BOOST_TEST (testset.erase(key_type(5)) == 1);
  248. BOOST_TEST (testset.empty() == true);
  249. //Now with a single bucket
  250. typename unordered_type::bucket_type single_bucket[1];
  251. unordered_type testset2(bucket_traits(
  252. pointer_traits<bucket_ptr>::pointer_to(single_bucket[0]), 1));
  253. testset2.insert(&values[0], &values[0] + values.size());
  254. BOOST_TEST (testset2.erase(key_type(5)) == 1);
  255. BOOST_TEST (testset2.erase(key_type(2)) == 2);
  256. BOOST_TEST (testset2.erase(key_type(1)) == 1);
  257. BOOST_TEST (testset2.erase(key_type(4)) == 1);
  258. BOOST_TEST (testset2.erase(key_type(3)) == 1);
  259. BOOST_TEST (testset2.empty() == true);
  260. }
  261. }
  262. {
  263. //Now erase just one per loop
  264. const int random_init[] = { 3, 2, 4, 1, 5, 2, 2 };
  265. const unsigned int random_size = sizeof(random_init)/sizeof(random_init[0]);
  266. typename unordered_type::bucket_type single_bucket[1];
  267. for(unsigned int i = 0, max = random_size; i != max; ++i){
  268. value_cont_type data (random_size);
  269. for (unsigned int j = 0; j < random_size; ++j)
  270. data[j].value_ = random_init[j];
  271. unordered_type testset_new(bucket_traits(
  272. pointer_traits<bucket_ptr>::pointer_to(single_bucket[0]), 1));
  273. testset_new.insert(&data[0], &data[0]+max);
  274. testset_new.erase(testset_new.iterator_to(data[i]));
  275. BOOST_TEST (testset_new.size() == (max -1));
  276. }
  277. }
  278. }
  279. {
  280. const unsigned int LoadFactor = 3;
  281. const unsigned int NumIterations = BucketSize*LoadFactor;
  282. value_cont_type random_init(NumIterations);//Preserve memory
  283. value_cont_type set_tester;
  284. set_tester.reserve(NumIterations);
  285. //Initialize values
  286. for (unsigned int i = 0; i < NumIterations; ++i){
  287. random_init[i].value_ = i*2;//(i/LoadFactor)*LoadFactor;
  288. }
  289. typename unordered_type::bucket_type buckets [BucketSize];
  290. bucket_traits btraits(pointer_traits<bucket_ptr>::pointer_to(buckets[0]), BucketSize);
  291. for(unsigned int initial_pos = 0; initial_pos != (NumIterations+1); ++initial_pos){
  292. for(unsigned int final_pos = initial_pos; final_pos != (NumIterations+1); ++final_pos){
  293. //Create intrusive container inserting values
  294. unordered_type testset
  295. ( random_init.data()
  296. , random_init.data() + random_init.size()
  297. , btraits);
  298. BOOST_TEST (testset.size() == random_init.size());
  299. //Obtain the iterator range to erase
  300. iterator it_beg_pos = testset.begin();
  301. for(unsigned int it_beg_pos_num = 0; it_beg_pos_num != initial_pos; ++it_beg_pos_num){
  302. ++it_beg_pos;
  303. }
  304. iterator it_end_pos(it_beg_pos);
  305. for(unsigned int it_end_pos_num = 0; it_end_pos_num != (final_pos - initial_pos); ++it_end_pos_num){
  306. ++it_end_pos;
  307. }
  308. //Erase the same values in both the intrusive and original vector
  309. std::size_t erased_cnt = boost::intrusive::iterator_distance(it_beg_pos, it_end_pos);
  310. //Erase values from the intrusive container
  311. testset.erase(it_beg_pos, it_end_pos);
  312. BOOST_TEST (testset.size() == (random_init.size()-(final_pos - initial_pos)));
  313. //Now test...
  314. BOOST_TEST ((random_init.size() - erased_cnt) == testset.size());
  315. //Create an ordered copy of the intrusive container
  316. set_tester.insert(set_tester.end(), testset.begin(), testset.end());
  317. std::sort(set_tester.begin(), set_tester.end());
  318. {
  319. typename value_cont_type::iterator it = set_tester.begin(), itend = set_tester.end();
  320. typename value_cont_type::iterator random_init_it(random_init.begin());
  321. for( ; it != itend; ++it){
  322. while(!random_init_it->is_linked())
  323. ++random_init_it;
  324. BOOST_TEST(*it == *random_init_it);
  325. ++random_init_it;
  326. }
  327. }
  328. set_tester.clear();
  329. }
  330. }
  331. }
  332. }
  333. //test: insert (seq-version), swap, erase (seq-version), size:
  334. template<class ContainerDefiner>
  335. void test_unordered<ContainerDefiner>::test_swap(value_cont_type& values)
  336. {
  337. typedef typename ContainerDefiner::template container
  338. <>::type unordered_type;
  339. typedef typename unordered_type::bucket_traits bucket_traits;
  340. typedef typename unordered_type::bucket_ptr bucket_ptr;
  341. typename unordered_type::bucket_type buckets [BucketSize];
  342. typename unordered_type::bucket_type buckets2 [BucketSize];
  343. unordered_type testset1(&values[0], &values[0] + 2,
  344. bucket_traits(pointer_traits<bucket_ptr>::pointer_to(buckets[0]), BucketSize));
  345. unordered_type testset2(bucket_traits(
  346. pointer_traits<bucket_ptr>::pointer_to(buckets2[0]), BucketSize));
  347. testset2.insert (&values[0] + 2, &values[0] + 6);
  348. testset1.swap (testset2);
  349. if(unordered_type::incremental){
  350. { int init_values [] = { 4, 5, 1, 2 };
  351. TEST_INTRUSIVE_SEQUENCE_MAYBEUNIQUE( init_values, testset1 ); }
  352. { int init_values [] = { 2, 3 };
  353. TEST_INTRUSIVE_SEQUENCE_MAYBEUNIQUE( init_values, testset2 ); }
  354. testset1.erase (testset1.iterator_to(values[4]), testset1.end());
  355. BOOST_TEST (testset1.size() == 1);
  356. // BOOST_TEST (&testset1.front() == &values[3]);
  357. BOOST_TEST (&*testset1.begin() == &values[2]);
  358. }
  359. else{
  360. { int init_values [] = { 1, 2, 4, 5 };
  361. TEST_INTRUSIVE_SEQUENCE_MAYBEUNIQUE( init_values, testset1 ); }
  362. { int init_values [] = { 2, 3 };
  363. TEST_INTRUSIVE_SEQUENCE_MAYBEUNIQUE( init_values, testset2 ); }
  364. testset1.erase (testset1.iterator_to(values[5]), testset1.end());
  365. BOOST_TEST (testset1.size() == 1);
  366. // BOOST_TEST (&testset1.front() == &values[3]);
  367. BOOST_TEST (&*testset1.begin() == &values[3]);
  368. }
  369. }
  370. //test: rehash:
  371. template<class ContainerDefiner>
  372. void test_unordered<ContainerDefiner>::test_rehash(value_cont_type& values, detail::true_)
  373. {
  374. typedef typename ContainerDefiner::template container
  375. <>::type unordered_type;
  376. typedef typename unordered_type::bucket_traits bucket_traits;
  377. typedef typename unordered_type::bucket_ptr bucket_ptr;
  378. //Build a uset
  379. typename unordered_type::bucket_type buckets1 [BucketSize];
  380. typename unordered_type::bucket_type buckets2 [BucketSize*2];
  381. unordered_type testset1(&values[0], &values[0] + values.size(),
  382. bucket_traits(pointer_traits<bucket_ptr>::
  383. pointer_to(buckets1[0]), BucketSize));
  384. //Test current state
  385. BOOST_TEST(testset1.split_count() == BucketSize/2);
  386. { int init_values [] = { 4, 5, 1, 2, 2, 3 };
  387. TEST_INTRUSIVE_SEQUENCE_MAYBEUNIQUE( init_values, testset1 ); }
  388. //Incremental rehash step
  389. BOOST_TEST (testset1.incremental_rehash() == true);
  390. BOOST_TEST(testset1.split_count() == (BucketSize/2+1));
  391. { int init_values [] = { 5, 1, 2, 2, 3, 4 };
  392. TEST_INTRUSIVE_SEQUENCE_MAYBEUNIQUE( init_values, testset1 ); }
  393. //Rest of incremental rehashes should lead to the same sequence
  394. for(std::size_t split_bucket = testset1.split_count(); split_bucket != BucketSize; ++split_bucket){
  395. BOOST_TEST (testset1.incremental_rehash() == true);
  396. BOOST_TEST(testset1.split_count() == (split_bucket+1));
  397. { int init_values [] = { 1, 2, 2, 3, 4, 5 };
  398. TEST_INTRUSIVE_SEQUENCE_MAYBEUNIQUE( init_values, testset1 ); }
  399. }
  400. //This incremental rehash should fail because we've reached the end of the bucket array
  401. BOOST_TEST (testset1.incremental_rehash() == false);
  402. BOOST_TEST(testset1.split_count() == BucketSize);
  403. { int init_values [] = { 1, 2, 2, 3, 4, 5 };
  404. TEST_INTRUSIVE_SEQUENCE_MAYBEUNIQUE( init_values, testset1 ); }
  405. //
  406. //Try incremental hashing specifying a new bucket traits pointing to the same array
  407. //
  408. //This incremental rehash should fail because the new size is not twice the original
  409. BOOST_TEST(testset1.incremental_rehash(bucket_traits(
  410. pointer_traits<bucket_ptr>::
  411. pointer_to(buckets1[0]), BucketSize)) == false);
  412. BOOST_TEST(testset1.split_count() == BucketSize);
  413. { int init_values [] = { 1, 2, 2, 3, 4, 5 };
  414. TEST_INTRUSIVE_SEQUENCE_MAYBEUNIQUE( init_values, testset1 ); }
  415. //
  416. //Try incremental hashing specifying a new bucket traits pointing to the same array
  417. //
  418. //This incremental rehash should fail because the new size is not twice the original
  419. BOOST_TEST(testset1.incremental_rehash(bucket_traits(
  420. pointer_traits<bucket_ptr>::
  421. pointer_to(buckets2[0]), BucketSize)) == false);
  422. BOOST_TEST(testset1.split_count() == BucketSize);
  423. { int init_values [] = { 1, 2, 2, 3, 4, 5 };
  424. TEST_INTRUSIVE_SEQUENCE_MAYBEUNIQUE( init_values, testset1 ); }
  425. //This incremental rehash should success because the new size is twice the original
  426. //and split_count is the same as the old bucket count
  427. BOOST_TEST(testset1.incremental_rehash(bucket_traits(
  428. pointer_traits<bucket_ptr>::
  429. pointer_to(buckets2[0]), BucketSize*2)) == true);
  430. BOOST_TEST(testset1.split_count() == BucketSize);
  431. { int init_values [] = { 1, 2, 2, 3, 4, 5 };
  432. TEST_INTRUSIVE_SEQUENCE_MAYBEUNIQUE( init_values, testset1 ); }
  433. //This incremental rehash should also success because the new size is half the original
  434. //and split_count is the same as the new bucket count
  435. BOOST_TEST(testset1.incremental_rehash(bucket_traits(
  436. pointer_traits<bucket_ptr>::
  437. pointer_to(buckets1[0]), BucketSize)) == true);
  438. BOOST_TEST(testset1.split_count() == BucketSize);
  439. { int init_values [] = { 1, 2, 2, 3, 4, 5 };
  440. TEST_INTRUSIVE_SEQUENCE_MAYBEUNIQUE( init_values, testset1 ); }
  441. //Shrink rehash
  442. testset1.rehash(bucket_traits(
  443. pointer_traits<bucket_ptr>::
  444. pointer_to(buckets1[0]), 4));
  445. BOOST_TEST (testset1.incremental_rehash() == false);
  446. { int init_values [] = { 4, 5, 1, 2, 2, 3 };
  447. TEST_INTRUSIVE_SEQUENCE_MAYBEUNIQUE( init_values, testset1 ); }
  448. //Shrink rehash again
  449. testset1.rehash(bucket_traits(
  450. pointer_traits<bucket_ptr>::
  451. pointer_to(buckets1[0]), 2));
  452. BOOST_TEST (testset1.incremental_rehash() == false);
  453. { int init_values [] = { 2, 2, 4, 3, 5, 1 };
  454. TEST_INTRUSIVE_SEQUENCE_MAYBEUNIQUE( init_values, testset1 ); }
  455. //Growing rehash
  456. testset1.rehash(bucket_traits(
  457. pointer_traits<bucket_ptr>::
  458. pointer_to(buckets1[0]), BucketSize));
  459. //Full rehash (no effects)
  460. testset1.full_rehash();
  461. { int init_values [] = { 1, 2, 2, 3, 4, 5 };
  462. TEST_INTRUSIVE_SEQUENCE_MAYBEUNIQUE( init_values, testset1 ); }
  463. //Incremental rehash shrinking
  464. //First incremental rehashes should lead to the same sequence
  465. for(std::size_t split_bucket = testset1.split_count(); split_bucket > 6; --split_bucket){
  466. BOOST_TEST (testset1.incremental_rehash(false) == true);
  467. BOOST_TEST(testset1.split_count() == (split_bucket-1));
  468. { int init_values [] = { 1, 2, 2, 3, 4, 5 };
  469. TEST_INTRUSIVE_SEQUENCE_MAYBEUNIQUE( init_values, testset1 ); }
  470. }
  471. //Incremental rehash step
  472. BOOST_TEST (testset1.incremental_rehash(false) == true);
  473. BOOST_TEST(testset1.split_count() == (BucketSize/2+1));
  474. { int init_values [] = { 5, 1, 2, 2, 3, 4 };
  475. TEST_INTRUSIVE_SEQUENCE_MAYBEUNIQUE( init_values, testset1 ); }
  476. //Incremental rehash step 2
  477. BOOST_TEST (testset1.incremental_rehash(false) == true);
  478. BOOST_TEST(testset1.split_count() == (BucketSize/2));
  479. { int init_values [] = { 4, 5, 1, 2, 2, 3 };
  480. TEST_INTRUSIVE_SEQUENCE_MAYBEUNIQUE( init_values, testset1 ); }
  481. //This incremental rehash should fail because we've reached the half of the bucket array
  482. BOOST_TEST(testset1.incremental_rehash(false) == false);
  483. BOOST_TEST(testset1.split_count() == BucketSize/2);
  484. { int init_values [] = { 4, 5, 1, 2, 2, 3 };
  485. TEST_INTRUSIVE_SEQUENCE_MAYBEUNIQUE( init_values, testset1 ); }
  486. }
  487. template<class ContainerDefiner>
  488. void test_unordered<ContainerDefiner>::test_rehash(value_cont_type& values, detail::false_)
  489. {
  490. typedef typename ContainerDefiner::template container
  491. <>::type unordered_type;
  492. typedef typename unordered_type::bucket_traits bucket_traits;
  493. typedef typename unordered_type::bucket_ptr bucket_ptr;
  494. typename unordered_type::bucket_type buckets1 [BucketSize];
  495. typename unordered_type::bucket_type buckets2 [2];
  496. typename unordered_type::bucket_type buckets3 [BucketSize*2];
  497. unordered_type testset1(&values[0], &values[0] + 6, bucket_traits(
  498. pointer_traits<bucket_ptr>::
  499. pointer_to(buckets1[0]), BucketSize));
  500. { int init_values [] = { 1, 2, 2, 3, 4, 5 };
  501. TEST_INTRUSIVE_SEQUENCE_MAYBEUNIQUE( init_values, testset1 ); }
  502. testset1.rehash(bucket_traits(
  503. pointer_traits<bucket_ptr>::pointer_to(buckets2[0]), 2));
  504. { int init_values [] = { 4, 2, 2, 5, 3, 1 };
  505. TEST_INTRUSIVE_SEQUENCE_MAYBEUNIQUE( init_values, testset1 ); }
  506. testset1.rehash(bucket_traits(
  507. pointer_traits<bucket_ptr>::pointer_to(buckets3[0]), BucketSize*2));
  508. { int init_values [] = { 1, 2, 2, 3, 4, 5 };
  509. TEST_INTRUSIVE_SEQUENCE_MAYBEUNIQUE( init_values, testset1 ); }
  510. //Now rehash reducing the buckets
  511. testset1.rehash(bucket_traits(
  512. pointer_traits<bucket_ptr>::pointer_to(buckets3[0]), 2));
  513. { int init_values [] = { 4, 2, 2, 5, 3, 1 };
  514. TEST_INTRUSIVE_SEQUENCE_MAYBEUNIQUE( init_values, testset1 ); }
  515. //Now rehash increasing the buckets
  516. testset1.rehash(bucket_traits(
  517. pointer_traits<bucket_ptr>::pointer_to(buckets3[0]), BucketSize*2));
  518. { int init_values [] = { 1, 2, 2, 3, 4, 5 };
  519. TEST_INTRUSIVE_SEQUENCE_MAYBEUNIQUE( init_values, testset1 ); }
  520. //Full rehash (no effects)
  521. testset1.full_rehash();
  522. { int init_values [] = { 1, 2, 2, 3, 4, 5 };
  523. TEST_INTRUSIVE_SEQUENCE_MAYBEUNIQUE( init_values, testset1 ); }
  524. }
  525. //test: find, equal_range (lower_bound, upper_bound):
  526. template<class ContainerDefiner>
  527. void test_unordered<ContainerDefiner>::test_find(value_cont_type& values)
  528. {
  529. typedef typename ContainerDefiner::template container
  530. <>::type unordered_type;
  531. typedef typename unordered_type::value_type value_type;
  532. typedef typename unordered_type::bucket_traits bucket_traits;
  533. typedef typename unordered_type::bucket_ptr bucket_ptr;
  534. typedef typename unordered_type::key_of_value key_of_value;
  535. const bool is_multikey = boost::intrusive::test::is_multikey_true<unordered_type>::value;
  536. typename unordered_type::bucket_type buckets[BucketSize];
  537. unordered_type testset(values.begin(), values.end(), bucket_traits(
  538. pointer_traits<bucket_ptr>::pointer_to(buckets[0]), BucketSize));
  539. typedef typename unordered_type::iterator iterator;
  540. value_type cmp_val;
  541. cmp_val.value_ = 2;
  542. BOOST_TEST (testset.count(key_of_value()(cmp_val)) == (is_multikey ? 2 : 1));
  543. iterator i = testset.find (key_of_value()(cmp_val));
  544. BOOST_TEST (i->value_ == 2);
  545. if(is_multikey)
  546. BOOST_TEST ((++i)->value_ == 2);
  547. else
  548. BOOST_TEST ((++i)->value_ != 2);
  549. std::pair<iterator,iterator> range = testset.equal_range (key_of_value()(cmp_val));
  550. BOOST_TEST (range.first->value_ == 2);
  551. BOOST_TEST (range.second->value_ == 3);
  552. BOOST_TEST (boost::intrusive::iterator_distance (range.first, range.second) == (is_multikey ? 2 : 1));
  553. cmp_val.value_ = 7;
  554. BOOST_TEST (testset.find (key_of_value()(cmp_val)) == testset.end());
  555. BOOST_TEST (testset.count(key_of_value()(cmp_val)) == 0);
  556. }
  557. template<class ContainerDefiner>
  558. void test_unordered<ContainerDefiner>::test_clone(value_cont_type& values)
  559. {
  560. typedef typename ContainerDefiner::template container
  561. <>::type unordered_type;
  562. typedef typename unordered_type::value_type value_type;
  563. typedef std::multiset<value_type> std_multiset_t;
  564. typedef typename unordered_type::bucket_traits bucket_traits;
  565. typedef typename unordered_type::bucket_ptr bucket_ptr;
  566. {
  567. //Test with equal bucket arrays
  568. typename unordered_type::bucket_type buckets1 [BucketSize];
  569. typename unordered_type::bucket_type buckets2 [BucketSize];
  570. unordered_type testset1 (values.begin(), values.end(), bucket_traits(
  571. pointer_traits<bucket_ptr>::pointer_to(buckets1[0]), BucketSize));
  572. unordered_type testset2 (bucket_traits(
  573. pointer_traits<bucket_ptr>::pointer_to(buckets2[0]), BucketSize));
  574. testset2.clone_from(testset1, test::new_cloner<value_type>(), test::delete_disposer<value_type>());
  575. BOOST_TEST(testset1 == testset2);
  576. //Ordering is not guarantee in the cloning so insert data in a set and test
  577. std_multiset_t src(testset1.begin(), testset1.end());
  578. std_multiset_t dst(testset2.begin(), testset2.end());
  579. BOOST_TEST (src.size() == dst.size() && std::equal(src.begin(), src.end(), dst.begin()));
  580. testset2.clear_and_dispose(test::delete_disposer<value_type>());
  581. BOOST_TEST (testset2.empty());
  582. testset2.clone_from(boost::move(testset1), test::new_nonconst_cloner<value_type>(), test::delete_disposer<value_type>());
  583. BOOST_TEST(testset1 == testset2);
  584. //Ordering is not guarantee in the cloning so insert data in a set and test
  585. std_multiset_t(testset1.begin(), testset1.end()).swap(src);
  586. std_multiset_t(testset2.begin(), testset2.end()).swap(dst);
  587. BOOST_TEST(src.size() == dst.size() && std::equal(src.begin(), src.end(), dst.begin()));
  588. testset2.clear_and_dispose(test::delete_disposer<value_type>());
  589. BOOST_TEST (testset2.empty());
  590. }
  591. {
  592. //Test with bigger source bucket arrays
  593. typename unordered_type::bucket_type buckets1 [BucketSize*2];
  594. typename unordered_type::bucket_type buckets2 [BucketSize];
  595. unordered_type testset1 (values.begin(), values.end(), bucket_traits(
  596. pointer_traits<bucket_ptr>::pointer_to(buckets1[0]), BucketSize*2));
  597. unordered_type testset2 (bucket_traits(
  598. pointer_traits<bucket_ptr>::pointer_to(buckets2[0]), BucketSize));
  599. testset2.clone_from(testset1, test::new_cloner<value_type>(), test::delete_disposer<value_type>());
  600. BOOST_TEST(testset1 == testset2);
  601. //Ordering is not guarantee in the cloning so insert data in a set and test
  602. std_multiset_t src(testset1.begin(), testset1.end());
  603. std_multiset_t dst(testset2.begin(), testset2.end());
  604. BOOST_TEST (src.size() == dst.size() && std::equal(src.begin(), src.end(), dst.begin()));
  605. testset2.clear_and_dispose(test::delete_disposer<value_type>());
  606. BOOST_TEST (testset2.empty());
  607. testset2.clone_from(boost::move(testset1), test::new_nonconst_cloner<value_type>(), test::delete_disposer<value_type>());
  608. BOOST_TEST(testset1 == testset2);
  609. //Ordering is not guarantee in the cloning so insert data in a set and test
  610. std_multiset_t(testset1.begin(), testset1.end()).swap(src);
  611. std_multiset_t(testset2.begin(), testset2.end()).swap(dst);
  612. BOOST_TEST (src.size() == dst.size() && std::equal(src.begin(), src.end(), dst.begin()));
  613. testset2.clear_and_dispose(test::delete_disposer<value_type>());
  614. BOOST_TEST (testset2.empty());
  615. }
  616. {
  617. //Test with smaller source bucket arrays
  618. typename unordered_type::bucket_type buckets1 [BucketSize];
  619. typename unordered_type::bucket_type buckets2 [BucketSize*2];
  620. unordered_type testset1 (values.begin(), values.end(), bucket_traits(
  621. pointer_traits<bucket_ptr>::pointer_to(buckets1[0]), BucketSize));
  622. unordered_type testset2 (bucket_traits(
  623. pointer_traits<bucket_ptr>::pointer_to(buckets2[0]), BucketSize*2));
  624. testset2.clone_from(testset1, test::new_cloner<value_type>(), test::delete_disposer<value_type>());
  625. BOOST_TEST(testset1 == testset2);
  626. //Ordering is not guaranteed in the cloning so insert data in a set and test
  627. std_multiset_t src(testset1.begin(), testset1.end());
  628. std_multiset_t dst(testset2.begin(), testset2.end());
  629. BOOST_TEST (src.size() == dst.size() && std::equal(src.begin(), src.end(), dst.begin()));
  630. testset2.clear_and_dispose(test::delete_disposer<value_type>());
  631. BOOST_TEST (testset2.empty());
  632. testset2.clone_from(boost::move(testset1), test::new_nonconst_cloner<value_type>(), test::delete_disposer<value_type>());
  633. BOOST_TEST(testset1 == testset2);
  634. //Ordering is not guaranteed in the cloning so insert data in a set and test
  635. std_multiset_t(testset1.begin(), testset1.end()).swap(src);
  636. std_multiset_t(testset2.begin(), testset2.end()).swap(dst);
  637. BOOST_TEST (src.size() == dst.size() && std::equal(src.begin(), src.end(), dst.begin()));
  638. testset2.clear_and_dispose(test::delete_disposer<value_type>());
  639. BOOST_TEST (testset2.empty());
  640. }
  641. }
  642. } //namespace test{
  643. } //namespace intrusive{
  644. } //namespace boost{