intrlist_ut.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512
  1. #include "intrlist.h"
  2. #include <library/cpp/testing/unittest/registar.h>
  3. #include <util/stream/output.h>
  4. class TListTest: public TTestBase {
  5. UNIT_TEST_SUITE(TListTest);
  6. UNIT_TEST(TestIterate);
  7. UNIT_TEST(TestRIterate);
  8. UNIT_TEST(TestForEach);
  9. UNIT_TEST(TestForEachWithDelete);
  10. UNIT_TEST(TestSize);
  11. UNIT_TEST(TestQuickSort);
  12. UNIT_TEST(TestCut);
  13. UNIT_TEST(TestAppend);
  14. UNIT_TEST(TestMoveCtor);
  15. UNIT_TEST(TestMoveOpEq);
  16. UNIT_TEST(TestListWithAutoDelete);
  17. UNIT_TEST(TestListWithAutoDeleteMoveCtor);
  18. UNIT_TEST(TestListWithAutoDeleteMoveOpEq);
  19. UNIT_TEST(TestListWithAutoDeleteClear);
  20. UNIT_TEST(TestSecondTag);
  21. UNIT_TEST_SUITE_END();
  22. private:
  23. void TestSize();
  24. void TestIterate();
  25. void TestRIterate();
  26. void TestForEach();
  27. void TestForEachWithDelete();
  28. void TestQuickSort();
  29. void TestCut();
  30. void TestAppend();
  31. void TestMoveCtor();
  32. void TestMoveOpEq();
  33. void TestListWithAutoDelete();
  34. void TestListWithAutoDeleteMoveCtor();
  35. void TestListWithAutoDeleteMoveOpEq();
  36. void TestListWithAutoDeleteClear();
  37. void TestSecondTag();
  38. };
  39. UNIT_TEST_SUITE_REGISTRATION(TListTest);
  40. class TInt: public TIntrusiveListItem<TInt> {
  41. public:
  42. inline TInt(int value) noexcept
  43. : Value_(value)
  44. {
  45. }
  46. TInt(TInt&& rhs) noexcept
  47. : Value_(rhs.Value_)
  48. {
  49. rhs.Value_ = 0xDEAD;
  50. }
  51. TInt& operator=(TInt&& rhs) noexcept {
  52. Value_ = rhs.Value_;
  53. rhs.Value_ = 0xBEEF;
  54. return *this;
  55. }
  56. inline operator int&() noexcept {
  57. return Value_;
  58. }
  59. inline operator const int&() const noexcept {
  60. return Value_;
  61. }
  62. private:
  63. int Value_;
  64. };
  65. class TMyList: public TIntrusiveList<TInt> {
  66. public:
  67. inline TMyList(int count) {
  68. while (count > 0) {
  69. PushFront(new TInt(count--));
  70. }
  71. }
  72. // TMyList(const TMyList& rhs) = default;
  73. TMyList(TMyList&& rhs) noexcept = default;
  74. // operator=(const TMyList& rhs) = default;
  75. TMyList& operator=(TMyList&& rhs) noexcept = default;
  76. inline ~TMyList() {
  77. while (!Empty()) {
  78. delete PopBack();
  79. }
  80. }
  81. };
  82. struct TIntGreater: private TGreater<int> {
  83. inline bool operator()(const TInt& l, const TInt& r) const noexcept {
  84. return TGreater<int>::operator()(l, r);
  85. }
  86. };
  87. void TListTest::TestQuickSort() {
  88. TMyList l(1000);
  89. size_t c = 0;
  90. l.QuickSort(TIntGreater());
  91. UNIT_ASSERT_EQUAL(l.Size(), 1000);
  92. for (TMyList::TIterator it = l.Begin(); it != l.End(); ++it) {
  93. UNIT_ASSERT_EQUAL(*it, int(1000 - c++));
  94. }
  95. }
  96. void TListTest::TestSize() {
  97. TMyList l(1024);
  98. UNIT_ASSERT_EQUAL(l.Size(), 1024);
  99. }
  100. void TListTest::TestIterate() {
  101. TMyList l(1000);
  102. size_t c = 0;
  103. for (TMyList::TIterator it = l.Begin(); it != l.End(); ++it) {
  104. ++c;
  105. UNIT_ASSERT_EQUAL(*it, (int)c);
  106. }
  107. UNIT_ASSERT_EQUAL(c, 1000);
  108. }
  109. void TListTest::TestRIterate() {
  110. TMyList l(1000);
  111. size_t c = 1000;
  112. UNIT_ASSERT_EQUAL(l.RBegin(), TMyList::TReverseIterator(l.End()));
  113. UNIT_ASSERT_EQUAL(l.REnd(), TMyList::TReverseIterator(l.Begin()));
  114. for (TMyList::TReverseIterator it = l.RBegin(); it != l.REnd(); ++it) {
  115. UNIT_ASSERT_EQUAL(*it, (int)c--);
  116. }
  117. UNIT_ASSERT_EQUAL(c, 0);
  118. }
  119. class TSum {
  120. public:
  121. inline TSum(size_t& sum)
  122. : Sum_(sum)
  123. {
  124. }
  125. inline void operator()(const TInt* v) noexcept {
  126. Sum_ += *v;
  127. }
  128. private:
  129. size_t& Sum_;
  130. };
  131. class TSumWithDelete {
  132. public:
  133. inline TSumWithDelete(size_t& sum)
  134. : Sum_(sum)
  135. {
  136. }
  137. inline void operator()(TInt* v) noexcept {
  138. if (*v % 2) {
  139. Sum_ += *v;
  140. } else {
  141. delete v;
  142. }
  143. }
  144. private:
  145. size_t& Sum_;
  146. };
  147. void TListTest::TestForEach() {
  148. TMyList l(1000);
  149. size_t sum = 0;
  150. TSum functor(sum);
  151. l.ForEach(functor);
  152. UNIT_ASSERT_EQUAL(sum, 1000 * 1001 / 2);
  153. }
  154. void TListTest::TestForEachWithDelete() {
  155. TMyList l(1000);
  156. size_t sum = 0;
  157. TSumWithDelete functor(sum);
  158. l.ForEach(functor);
  159. UNIT_ASSERT_EQUAL(sum, 500 * 500 /*== n * (x + y * (n - 1) / 2), x == 1, y == 2*/);
  160. }
  161. static void CheckIterationAfterCut(const TMyList& l, const TMyList& l2, size_t N, size_t M) {
  162. size_t c = 0;
  163. for (TMyList::TConstIterator it = l.Begin(); it != l.End(); ++it) {
  164. ++c;
  165. UNIT_ASSERT_EQUAL(*it, (int)c);
  166. }
  167. UNIT_ASSERT_EQUAL(c, M);
  168. for (TMyList::TConstIterator it = l2.Begin(); it != l2.End(); ++it) {
  169. ++c;
  170. UNIT_ASSERT_EQUAL(*it, (int)c);
  171. }
  172. UNIT_ASSERT_EQUAL(c, N);
  173. for (TMyList::TConstIterator it = l2.End(); it != l2.Begin(); --c) {
  174. --it;
  175. UNIT_ASSERT_EQUAL(*it, (int)c);
  176. }
  177. UNIT_ASSERT_EQUAL(c, M);
  178. for (TMyList::TConstIterator it = l.End(); it != l.Begin(); --c) {
  179. --it;
  180. UNIT_ASSERT_EQUAL(*it, (int)c);
  181. }
  182. UNIT_ASSERT_EQUAL(c, 0);
  183. }
  184. static void TestCutFront(int N, int M) {
  185. TMyList l(N);
  186. TMyList l2(0);
  187. TMyList::TIterator it = l.Begin();
  188. for (int i = 0; i < M; ++i) {
  189. ++it;
  190. }
  191. TMyList::Cut(l.Begin(), it, l2.End());
  192. CheckIterationAfterCut(l2, l, N, M);
  193. }
  194. static void TestCutBack(int N, int M) {
  195. TMyList l(N);
  196. TMyList l2(0);
  197. TMyList::TIterator it = l.Begin();
  198. for (int i = 0; i < M; ++i) {
  199. ++it;
  200. }
  201. TMyList::Cut(it, l.End(), l2.End());
  202. CheckIterationAfterCut(l, l2, N, M);
  203. }
  204. void TListTest::TestCut() {
  205. TestCutFront(1000, 500);
  206. TestCutBack(1000, 500);
  207. TestCutFront(1, 0);
  208. TestCutBack(1, 0);
  209. TestCutFront(1, 1);
  210. TestCutBack(1, 1);
  211. TestCutFront(2, 0);
  212. TestCutBack(2, 0);
  213. TestCutFront(2, 1);
  214. TestCutBack(2, 1);
  215. TestCutFront(2, 2);
  216. TestCutBack(2, 2);
  217. }
  218. static void CheckIterationAfterAppend(const TMyList& l, size_t N, size_t M) {
  219. TMyList::TConstIterator it = l.Begin();
  220. for (size_t i = 1; i <= N; ++i, ++it) {
  221. UNIT_ASSERT_EQUAL((int)i, *it);
  222. }
  223. for (size_t i = 1; i <= M; ++i, ++it) {
  224. UNIT_ASSERT_EQUAL((int)i, *it);
  225. }
  226. UNIT_ASSERT_EQUAL(it, l.End());
  227. }
  228. static void TestAppend(int N, int M) {
  229. TMyList l(N);
  230. TMyList l2(M);
  231. l.Append(l2);
  232. UNIT_ASSERT(l2.Empty());
  233. CheckIterationAfterAppend(l, N, M);
  234. }
  235. void TListTest::TestAppend() {
  236. ::TestAppend(500, 500);
  237. ::TestAppend(0, 0);
  238. ::TestAppend(1, 0);
  239. ::TestAppend(0, 1);
  240. ::TestAppend(1, 1);
  241. }
  242. template <typename TListType>
  243. static void CheckList(const TListType& lst) {
  244. int i = 1;
  245. for (typename TListType::TConstIterator it = lst.Begin(); it != lst.End(); ++it, ++i) {
  246. UNIT_ASSERT_EQUAL(*it, i);
  247. }
  248. }
  249. void TListTest::TestMoveCtor() {
  250. const int N{42};
  251. TMyList lst{N};
  252. UNIT_ASSERT(!lst.Empty());
  253. UNIT_ASSERT_EQUAL(lst.Size(), N);
  254. CheckList(lst);
  255. TMyList nextLst{std::move(lst)};
  256. UNIT_ASSERT(lst.Empty());
  257. CheckList(nextLst);
  258. }
  259. void TListTest::TestMoveOpEq() {
  260. const int N{42};
  261. TMyList lst{N};
  262. UNIT_ASSERT(!lst.Empty());
  263. UNIT_ASSERT_EQUAL(lst.Size(), N);
  264. CheckList(lst);
  265. const int M{2};
  266. TMyList nextLst(M);
  267. UNIT_ASSERT(!nextLst.Empty());
  268. UNIT_ASSERT_EQUAL(nextLst.Size(), M);
  269. CheckList(nextLst);
  270. nextLst = std::move(lst);
  271. UNIT_ASSERT(!nextLst.Empty());
  272. UNIT_ASSERT_EQUAL(nextLst.Size(), N);
  273. CheckList(nextLst);
  274. }
  275. class TSelfCountingInt: public TIntrusiveListItem<TSelfCountingInt> {
  276. public:
  277. TSelfCountingInt(int& counter, int value) noexcept
  278. : Counter_(counter)
  279. , Value_(value)
  280. {
  281. ++Counter_;
  282. }
  283. TSelfCountingInt(TSelfCountingInt&& rhs) noexcept
  284. : Counter_(rhs.Counter_)
  285. , Value_(rhs.Value_)
  286. {
  287. rhs.Value_ = 0xDEAD;
  288. }
  289. TSelfCountingInt& operator=(TSelfCountingInt&& rhs) noexcept {
  290. Value_ = rhs.Value_;
  291. rhs.Value_ = 0xBEEF;
  292. return *this;
  293. }
  294. ~TSelfCountingInt() noexcept {
  295. --Counter_;
  296. }
  297. inline operator int&() noexcept {
  298. return Value_;
  299. }
  300. inline operator const int&() const noexcept {
  301. return Value_;
  302. }
  303. private:
  304. int& Counter_;
  305. int Value_;
  306. };
  307. struct TSelfCountingIntDelete {
  308. static void Destroy(TSelfCountingInt* i) noexcept {
  309. delete i;
  310. }
  311. };
  312. void TListTest::TestListWithAutoDelete() {
  313. using TListType = TIntrusiveListWithAutoDelete<TSelfCountingInt, TSelfCountingIntDelete>;
  314. int counter{0};
  315. {
  316. TListType lst;
  317. UNIT_ASSERT(lst.Empty());
  318. lst.PushFront(new TSelfCountingInt(counter, 2));
  319. UNIT_ASSERT_EQUAL(lst.Size(), 1);
  320. UNIT_ASSERT_EQUAL(counter, 1);
  321. lst.PushFront(new TSelfCountingInt(counter, 1));
  322. UNIT_ASSERT_EQUAL(lst.Size(), 2);
  323. UNIT_ASSERT_EQUAL(counter, 2);
  324. CheckList(lst);
  325. }
  326. UNIT_ASSERT_EQUAL(counter, 0);
  327. }
  328. void TListTest::TestListWithAutoDeleteMoveCtor() {
  329. using TListType = TIntrusiveListWithAutoDelete<TSelfCountingInt, TSelfCountingIntDelete>;
  330. int counter{0};
  331. {
  332. TListType lst;
  333. lst.PushFront(new TSelfCountingInt(counter, 2));
  334. lst.PushFront(new TSelfCountingInt(counter, 1));
  335. UNIT_ASSERT_EQUAL(lst.Size(), 2);
  336. UNIT_ASSERT_EQUAL(counter, 2);
  337. CheckList(lst);
  338. TListType nextList(std::move(lst));
  339. UNIT_ASSERT_EQUAL(nextList.Size(), 2);
  340. CheckList(nextList);
  341. UNIT_ASSERT_EQUAL(counter, 2);
  342. }
  343. UNIT_ASSERT_EQUAL(counter, 0);
  344. }
  345. void TListTest::TestListWithAutoDeleteMoveOpEq() {
  346. using TListType = TIntrusiveListWithAutoDelete<TSelfCountingInt, TSelfCountingIntDelete>;
  347. int counter{0};
  348. {
  349. TListType lst;
  350. lst.PushFront(new TSelfCountingInt(counter, 2));
  351. lst.PushFront(new TSelfCountingInt(counter, 1));
  352. UNIT_ASSERT_EQUAL(lst.Size(), 2);
  353. UNIT_ASSERT_EQUAL(counter, 2);
  354. CheckList(lst);
  355. TListType nextList;
  356. UNIT_ASSERT(nextList.Empty());
  357. nextList = std::move(lst);
  358. UNIT_ASSERT_EQUAL(nextList.Size(), 2);
  359. CheckList(nextList);
  360. UNIT_ASSERT_EQUAL(counter, 2);
  361. }
  362. UNIT_ASSERT_EQUAL(counter, 0);
  363. }
  364. void TListTest::TestListWithAutoDeleteClear() {
  365. using TListType = TIntrusiveListWithAutoDelete<TSelfCountingInt, TSelfCountingIntDelete>;
  366. int counter{0};
  367. {
  368. TListType lst;
  369. UNIT_ASSERT(lst.Empty());
  370. lst.PushFront(new TSelfCountingInt(counter, 2));
  371. UNIT_ASSERT_EQUAL(lst.Size(), 1);
  372. UNIT_ASSERT_EQUAL(counter, 1);
  373. lst.PushFront(new TSelfCountingInt(counter, 1));
  374. UNIT_ASSERT_EQUAL(lst.Size(), 2);
  375. UNIT_ASSERT_EQUAL(counter, 2);
  376. CheckList(lst);
  377. lst.Clear();
  378. UNIT_ASSERT(lst.Empty());
  379. UNIT_ASSERT_EQUAL(counter, 0);
  380. lst.PushFront(new TSelfCountingInt(counter, 1));
  381. UNIT_ASSERT_EQUAL(lst.Size(), 1);
  382. }
  383. UNIT_ASSERT_EQUAL(counter, 0);
  384. }
  385. struct TSecondTag {};
  386. class TDoubleNode
  387. : public TInt,
  388. public TIntrusiveListItem<TDoubleNode, TSecondTag> {
  389. public:
  390. TDoubleNode(int value) noexcept
  391. : TInt(value)
  392. {
  393. }
  394. };
  395. void TListTest::TestSecondTag() {
  396. TDoubleNode zero(0), one(1);
  397. TIntrusiveList<TInt> first;
  398. TIntrusiveList<TDoubleNode, TSecondTag> second;
  399. first.PushFront(&zero);
  400. first.PushFront(&one);
  401. second.PushBack(&zero);
  402. second.PushBack(&one);
  403. UNIT_ASSERT_EQUAL(*first.Front(), 1);
  404. UNIT_ASSERT_EQUAL(*++first.Begin(), 0);
  405. UNIT_ASSERT_EQUAL(*first.Back(), 0);
  406. UNIT_ASSERT_EQUAL(*second.Front(), 0);
  407. UNIT_ASSERT_EQUAL(*++second.Begin(), 1);
  408. UNIT_ASSERT_EQUAL(*second.Back(), 1);
  409. second.Remove(&zero);
  410. UNIT_ASSERT_EQUAL(*second.Front(), 1);
  411. UNIT_ASSERT_EQUAL(*first.Back(), 0);
  412. }