sl.hpp 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. #ifndef __XRCU_TESTS_SL__
  2. #define __XRCU_TESTS_SL__ 1
  3. #include "../skip_list.hpp"
  4. #include <thread>
  5. #include <cstdio>
  6. #include <cctype>
  7. #include "utils.hpp"
  8. typedef xrcu::skip_list<std::string> sklist_t;
  9. namespace sl_test
  10. {
  11. void test_single_threaded ()
  12. {
  13. sklist_t sl;
  14. ASSERT (sl.empty ());
  15. sl.assign ({ mkstr (-1), mkstr (-2), mkstr (-3) });
  16. ASSERT (sl.size () == 3);
  17. ASSERT (sl.upper_bound (mkstr (0)) == sl.end ());
  18. ASSERT (sl.lower_bound (std::string ("-0")) == sl.begin ());
  19. sl.clear ();
  20. ASSERT (sl.empty ());
  21. for (int i = 0; i < 1000; ++i)
  22. ASSERT (sl.insert (mkstr (i)));
  23. ASSERT (!sl.insert (mkstr (813)));
  24. ASSERT (sl.size () == 1000);
  25. auto prev = sl.remove (mkstr (101));
  26. ASSERT (prev.has_value ());
  27. ASSERT (*prev == mkstr (101));
  28. ASSERT (!sl.erase (mkstr (101)));
  29. ASSERT (sl.erase (mkstr (999)));
  30. for (const auto& s : sl)
  31. for (auto ch : s)
  32. ASSERT (isdigit (ch));
  33. {
  34. const int PIVOT = 572;
  35. auto it = sl.lower_bound (mkstr (PIVOT));
  36. ASSERT (it != sl.end ());
  37. ASSERT (*it == mkstr (PIVOT - 1));
  38. it = sl.upper_bound (mkstr (PIVOT));
  39. ASSERT (it != sl.end ());
  40. ASSERT (*it == mkstr (PIVOT + 1));
  41. sklist_t s2 { std::string ("aaa"), std::string ("bbb"),
  42. std::string ("ccc"), std::string ("ddd") };
  43. sl.swap (s2);
  44. ASSERT (sl.size () == 4);
  45. ASSERT (sl.contains (std::string ("aaa")));
  46. }
  47. ASSERT (!xrcu::in_cs ());
  48. }
  49. static void
  50. mt_inserter (sklist_t *sx, int index)
  51. {
  52. for (int i = 0; i < INSERTER_LOOPS; ++i)
  53. ASSERT (sx->insert (mkstr (index * INSERTER_LOOPS + i)));
  54. }
  55. static bool
  56. sl_consistent (sklist_t& sx)
  57. {
  58. if (sx.empty ())
  59. return (true);
  60. auto it = sx.begin ();
  61. std::string s1 = *it;
  62. for (++it; it != sx.end (); ++it)
  63. {
  64. std::string s2 = *it;
  65. if (!(s1 < s2))
  66. return (false);
  67. s1.swap (s2);
  68. }
  69. return (true);
  70. }
  71. void test_insert_mt ()
  72. {
  73. sklist_t sx;
  74. std::vector<std::thread> thrs;
  75. for (int i = 0; i < INSERTER_THREADS; ++i)
  76. thrs.push_back (std::thread (mt_inserter, &sx, i));
  77. for (auto& thr : thrs)
  78. thr.join ();
  79. ASSERT (sx.size () == INSERTER_THREADS * INSERTER_LOOPS);
  80. ASSERT (sl_consistent (sx));
  81. }
  82. static void
  83. mt_inserter_ov (sklist_t *sx, int index)
  84. {
  85. for (int i = 0; i < INSERTER_LOOPS; ++i)
  86. sx->insert (mkstr (index * (INSERTER_LOOPS / 2) + i));
  87. }
  88. void test_insert_mt_ov ()
  89. {
  90. sklist_t sx;
  91. std::vector<std::thread> thrs;
  92. for (int i = 0; i < INSERTER_THREADS; ++i)
  93. thrs.push_back (std::thread (mt_inserter_ov, &sx, i));
  94. for (auto& thr : thrs)
  95. thr.join ();
  96. ASSERT (sx.size () == (INSERTER_THREADS + 1) * INSERTER_LOOPS / 2);
  97. ASSERT (sl_consistent (sx));
  98. }
  99. static void
  100. mt_eraser (sklist_t *sx, int index)
  101. {
  102. for (int i = 0; i < ERASER_LOOPS; ++i)
  103. {
  104. auto prev = sx->remove (mkstr (index * ERASER_LOOPS + i));
  105. ASSERT (prev.has_value ());
  106. for (auto ch : *prev)
  107. ASSERT (isdigit (ch));
  108. }
  109. }
  110. static void
  111. fill_list_for_erase (sklist_t& sx)
  112. {
  113. for (int i = 0; i < ERASER_THREADS * ERASER_LOOPS; ++i)
  114. sx.insert (mkstr (i));
  115. }
  116. void test_erase_mt ()
  117. {
  118. sklist_t sx;
  119. fill_list_for_erase (sx);
  120. std::vector<std::thread> thrs;
  121. for (int i = 0; i < ERASER_THREADS; ++i)
  122. thrs.push_back (std::thread (mt_eraser, &sx, i));
  123. for (auto& thr : thrs)
  124. thr.join ();
  125. ASSERT (sx.empty ());
  126. }
  127. static void
  128. mt_eraser_ov (sklist_t *sx, int index)
  129. {
  130. for (int i = 0; i < ERASER_LOOPS; ++i)
  131. sx->erase (mkstr (index * (ERASER_LOOPS / 2) + i));
  132. }
  133. void test_erase_mt_ov ()
  134. {
  135. sklist_t sx;
  136. fill_list_for_erase (sx);
  137. std::vector<std::thread> thrs;
  138. for (int i = 0; i < ERASER_THREADS; ++i)
  139. thrs.push_back (std::thread (mt_eraser_ov, &sx, i));
  140. for (auto& thr : thrs)
  141. thr.join ();
  142. ASSERT (sx.size () == (ERASER_THREADS - 1) * ERASER_LOOPS / 2);
  143. ASSERT (sl_consistent (sx));
  144. }
  145. test_module skip_list_tests
  146. {
  147. "skip list",
  148. {
  149. { "API in a single thread", test_single_threaded },
  150. { "multi threaded insertions", test_insert_mt },
  151. { "multi threaded overlapped insertions", test_insert_mt_ov },
  152. { "multi threaded erasures", test_erase_mt },
  153. { "multi threaded overlapped erasures", test_erase_mt_ov }
  154. }
  155. };
  156. } // namespace sl_test
  157. #endif