ptr_ut.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964
  1. #include "ptr.h"
  2. #include "vector.h"
  3. #include "noncopyable.h"
  4. #include <library/cpp/testing/common/probe.h>
  5. #include <library/cpp/testing/unittest/registar.h>
  6. #include <util/generic/hash_set.h>
  7. #include <util/generic/is_in.h>
  8. #include <util/system/thread.h>
  9. class TPointerTest: public TTestBase {
  10. UNIT_TEST_SUITE(TPointerTest);
  11. UNIT_TEST(TestTypedefs);
  12. UNIT_TEST(TestSimpleIntrPtr);
  13. UNIT_TEST(TestHolderPtr);
  14. UNIT_TEST(TestHolderPtrMoveConstructor);
  15. UNIT_TEST(TestHolderPtrMoveConstructorInheritance);
  16. UNIT_TEST(TestHolderPtrMoveAssignment);
  17. UNIT_TEST(TestHolderPtrMoveAssignmentInheritance);
  18. UNIT_TEST(TestMakeHolder);
  19. UNIT_TEST(TestTrulePtr);
  20. UNIT_TEST(TestAutoToHolder);
  21. UNIT_TEST(TestCopyPtr);
  22. UNIT_TEST(TestIntrPtr);
  23. UNIT_TEST(TestIntrusiveConvertion);
  24. UNIT_TEST(TestIntrusiveConstConvertion);
  25. UNIT_TEST(TestIntrusiveConstConstruction);
  26. UNIT_TEST(TestMakeIntrusive);
  27. UNIT_TEST(TestCopyOnWritePtr1);
  28. UNIT_TEST(TestCopyOnWritePtr2);
  29. UNIT_TEST(TestOperatorBool);
  30. UNIT_TEST(TestMakeShared);
  31. UNIT_TEST(TestComparison);
  32. UNIT_TEST(TestSimpleIntrusivePtrCtorTsan);
  33. UNIT_TEST(TestRefCountedPtrsInHashSet);
  34. UNIT_TEST(TestSharedPtrDowncast);
  35. UNIT_TEST(TestStdCompatibility);
  36. UNIT_TEST_SUITE_END();
  37. private:
  38. void TestSimpleIntrusivePtrCtorTsan() {
  39. struct S: public TAtomicRefCount<S> {
  40. };
  41. struct TLocalThread: public ISimpleThread {
  42. void* ThreadProc() override {
  43. TSimpleIntrusivePtr<S> ptr;
  44. return nullptr;
  45. }
  46. };
  47. // Create TSimpleIntrusivePtr in different threads
  48. // Its constructor should be thread-safe
  49. TLocalThread t1, t2;
  50. t1.Start();
  51. t2.Start();
  52. t1.Join();
  53. t2.Join();
  54. }
  55. inline void TestTypedefs() {
  56. TAtomicSharedPtr<int>(new int(1));
  57. TSimpleSharedPtr<int>(new int(1));
  58. }
  59. void TestSimpleIntrPtr();
  60. void TestHolderPtr();
  61. void TestHolderPtrMoveConstructor();
  62. void TestHolderPtrMoveConstructorInheritance();
  63. void TestHolderPtrMoveAssignment();
  64. void TestHolderPtrMoveAssignmentInheritance();
  65. void TestMakeHolder();
  66. void TestTrulePtr();
  67. void TestAutoToHolder();
  68. void TestCopyPtr();
  69. void TestIntrPtr();
  70. void TestIntrusiveConvertion();
  71. void TestIntrusiveConstConvertion();
  72. void TestIntrusiveConstConstruction();
  73. void TestMakeIntrusive();
  74. void TestCopyOnWritePtr1();
  75. void TestCopyOnWritePtr2();
  76. void TestOperatorBool();
  77. void TestMakeShared();
  78. void TestComparison();
  79. template <class T, class TRefCountedPtr>
  80. void TestRefCountedPtrsInHashSetImpl();
  81. void TestRefCountedPtrsInHashSet();
  82. void TestSharedPtrDowncast();
  83. void TestStdCompatibility();
  84. };
  85. UNIT_TEST_SUITE_REGISTRATION(TPointerTest);
  86. static int cnt = 0;
  87. class A: public TAtomicRefCount<A> {
  88. public:
  89. inline A() {
  90. ++cnt;
  91. }
  92. inline A(const A&)
  93. : TAtomicRefCount<A>(*this)
  94. {
  95. ++cnt;
  96. }
  97. inline ~A() {
  98. --cnt;
  99. }
  100. };
  101. static A* MakeA() {
  102. return new A();
  103. }
  104. /*
  105. * test compileability
  106. */
  107. class B;
  108. static TSimpleIntrusivePtr<B> GetB() {
  109. throw 1;
  110. }
  111. void Func() {
  112. TSimpleIntrusivePtr<B> b = GetB();
  113. }
  114. void TPointerTest::TestSimpleIntrPtr() {
  115. {
  116. TSimpleIntrusivePtr<A> a1(MakeA());
  117. TSimpleIntrusivePtr<A> a2(MakeA());
  118. TSimpleIntrusivePtr<A> a3 = a2;
  119. a1 = a2;
  120. a2 = a3;
  121. }
  122. UNIT_ASSERT_VALUES_EQUAL(cnt, 0);
  123. }
  124. void TPointerTest::TestHolderPtr() {
  125. {
  126. THolder<A> a1(MakeA());
  127. THolder<A> a2(a1.Release());
  128. }
  129. UNIT_ASSERT_VALUES_EQUAL(cnt, 0);
  130. }
  131. THolder<int> CreateInt(int value) {
  132. THolder<int> res(new int);
  133. *res = value;
  134. return res;
  135. }
  136. void TPointerTest::TestHolderPtrMoveConstructor() {
  137. THolder<int> h = CreateInt(42);
  138. UNIT_ASSERT_VALUES_EQUAL(*h, 42);
  139. }
  140. void TPointerTest::TestHolderPtrMoveAssignment() {
  141. THolder<int> h(new int);
  142. h = CreateInt(42);
  143. UNIT_ASSERT_VALUES_EQUAL(*h, 42);
  144. }
  145. struct TBase {
  146. virtual ~TBase() = default;
  147. };
  148. struct TDerived: public TBase {
  149. };
  150. void TPointerTest::TestHolderPtrMoveConstructorInheritance() {
  151. // compileability test
  152. THolder<TBase> basePtr(THolder<TDerived>(new TDerived));
  153. }
  154. void TPointerTest::TestHolderPtrMoveAssignmentInheritance() {
  155. // compileability test
  156. THolder<TBase> basePtr;
  157. basePtr = THolder<TDerived>(new TDerived);
  158. }
  159. void TPointerTest::TestMakeHolder() {
  160. {
  161. auto ptr = MakeHolder<int>(5);
  162. UNIT_ASSERT_VALUES_EQUAL(*ptr, 5);
  163. }
  164. {
  165. struct TRec {
  166. int X, Y;
  167. TRec()
  168. : X(1)
  169. , Y(2)
  170. {
  171. }
  172. };
  173. THolder<TRec> ptr = MakeHolder<TRec>();
  174. UNIT_ASSERT_VALUES_EQUAL(ptr->X, 1);
  175. UNIT_ASSERT_VALUES_EQUAL(ptr->Y, 2);
  176. }
  177. {
  178. struct TRec {
  179. int X, Y;
  180. TRec(int x, int y)
  181. : X(x)
  182. , Y(y)
  183. {
  184. }
  185. };
  186. auto ptr = MakeHolder<TRec>(1, 2);
  187. UNIT_ASSERT_VALUES_EQUAL(ptr->X, 1);
  188. UNIT_ASSERT_VALUES_EQUAL(ptr->Y, 2);
  189. }
  190. {
  191. class TRec {
  192. private:
  193. int X_, Y_;
  194. public:
  195. TRec(int x, int y)
  196. : X_(x)
  197. , Y_(y)
  198. {
  199. }
  200. int GetX() const {
  201. return X_;
  202. }
  203. int GetY() const {
  204. return Y_;
  205. }
  206. };
  207. auto ptr = MakeHolder<TRec>(1, 2);
  208. UNIT_ASSERT_VALUES_EQUAL(ptr->GetX(), 1);
  209. UNIT_ASSERT_VALUES_EQUAL(ptr->GetY(), 2);
  210. }
  211. }
  212. void TPointerTest::TestTrulePtr() {
  213. {
  214. TAutoPtr<A> a1(MakeA());
  215. TAutoPtr<A> a2(a1);
  216. a1 = a2;
  217. }
  218. UNIT_ASSERT_VALUES_EQUAL(cnt, 0);
  219. }
  220. void TPointerTest::TestAutoToHolder() {
  221. {
  222. TAutoPtr<A> a1(MakeA());
  223. THolder<A> a2(a1);
  224. UNIT_ASSERT_EQUAL(a1.Get(), nullptr);
  225. UNIT_ASSERT_VALUES_EQUAL(cnt, 1);
  226. }
  227. UNIT_ASSERT_VALUES_EQUAL(cnt, 0);
  228. {
  229. TAutoPtr<A> x(new A());
  230. THolder<const A> y = x;
  231. }
  232. UNIT_ASSERT_VALUES_EQUAL(cnt, 0);
  233. {
  234. class B1: public A {
  235. };
  236. TAutoPtr<B1> x(new B1());
  237. THolder<A> y = x;
  238. }
  239. UNIT_ASSERT_VALUES_EQUAL(cnt, 0);
  240. }
  241. void TPointerTest::TestCopyPtr() {
  242. TCopyPtr<A> a1(MakeA());
  243. {
  244. TCopyPtr<A> a2(MakeA());
  245. TCopyPtr<A> a3 = a2;
  246. UNIT_ASSERT_VALUES_EQUAL(cnt, 3);
  247. a1 = a2;
  248. a2 = a3;
  249. }
  250. UNIT_ASSERT_VALUES_EQUAL(cnt, 1);
  251. a1.Destroy();
  252. UNIT_ASSERT_VALUES_EQUAL(cnt, 0);
  253. }
  254. class TOp: public TSimpleRefCount<TOp>, public TNonCopyable {
  255. public:
  256. static int Cnt;
  257. public:
  258. TOp() {
  259. ++Cnt;
  260. }
  261. virtual ~TOp() {
  262. --Cnt;
  263. }
  264. };
  265. int TOp::Cnt = 0;
  266. class TOp2: public TOp {
  267. public:
  268. TIntrusivePtr<TOp> Op;
  269. public:
  270. TOp2(const TIntrusivePtr<TOp>& op)
  271. : Op(op)
  272. {
  273. ++Cnt;
  274. }
  275. ~TOp2() override {
  276. --Cnt;
  277. }
  278. };
  279. class TOp3 {
  280. public:
  281. TIntrusivePtr<TOp2> Op2;
  282. };
  283. void Attach(TOp3* op3, TIntrusivePtr<TOp>* op) {
  284. TIntrusivePtr<TOp2> op2 = new TOp2(*op);
  285. op3->Op2 = op2.Get();
  286. *op = op2.Get();
  287. }
  288. void TPointerTest::TestIntrPtr() {
  289. {
  290. TIntrusivePtr<TOp> p, p2;
  291. TOp3 op3;
  292. {
  293. TVector<TIntrusivePtr<TOp>> f1;
  294. {
  295. TVector<TIntrusivePtr<TOp>> f2;
  296. f2.push_back(new TOp);
  297. p = new TOp;
  298. f2.push_back(p);
  299. Attach(&op3, &f2[1]);
  300. f1 = f2;
  301. UNIT_ASSERT_VALUES_EQUAL(f1[0]->RefCount(), 2);
  302. UNIT_ASSERT_VALUES_EQUAL(f1[1]->RefCount(), 3);
  303. UNIT_ASSERT_EQUAL(f1[1].Get(), op3.Op2.Get());
  304. UNIT_ASSERT_VALUES_EQUAL(op3.Op2->RefCount(), 3);
  305. UNIT_ASSERT_VALUES_EQUAL(op3.Op2->Op->RefCount(), 2);
  306. UNIT_ASSERT_VALUES_EQUAL(TOp::Cnt, 4);
  307. }
  308. p2 = p;
  309. }
  310. UNIT_ASSERT_VALUES_EQUAL(op3.Op2->RefCount(), 1);
  311. UNIT_ASSERT_VALUES_EQUAL(op3.Op2->Op->RefCount(), 3);
  312. UNIT_ASSERT_VALUES_EQUAL(TOp::Cnt, 3);
  313. }
  314. UNIT_ASSERT_VALUES_EQUAL(TOp::Cnt, 0);
  315. }
  316. namespace NTestIntrusiveConvertion {
  317. struct TA: public TSimpleRefCount<TA> {
  318. };
  319. struct TAA: public TA {
  320. };
  321. struct TB: public TSimpleRefCount<TB> {
  322. };
  323. void Func(TIntrusivePtr<TA>) {
  324. }
  325. void Func(TIntrusivePtr<TB>) {
  326. }
  327. void Func(TIntrusiveConstPtr<TA>) {
  328. }
  329. void Func(TIntrusiveConstPtr<TB>) {
  330. }
  331. } // namespace NTestIntrusiveConvertion
  332. void TPointerTest::TestIntrusiveConvertion() {
  333. using namespace NTestIntrusiveConvertion;
  334. TIntrusivePtr<TAA> aa = new TAA;
  335. UNIT_ASSERT_VALUES_EQUAL(aa->RefCount(), 1);
  336. TIntrusivePtr<TA> a = aa;
  337. UNIT_ASSERT_VALUES_EQUAL(aa->RefCount(), 2);
  338. UNIT_ASSERT_VALUES_EQUAL(a->RefCount(), 2);
  339. aa.Reset();
  340. UNIT_ASSERT_VALUES_EQUAL(a->RefCount(), 1);
  341. // test that Func(TIntrusivePtr<TB>) doesn't participate in overload resolution
  342. Func(aa);
  343. }
  344. void TPointerTest::TestIntrusiveConstConvertion() {
  345. using namespace NTestIntrusiveConvertion;
  346. TIntrusiveConstPtr<TAA> aa = new TAA;
  347. UNIT_ASSERT_VALUES_EQUAL(aa->RefCount(), 1);
  348. TIntrusiveConstPtr<TA> a = aa;
  349. UNIT_ASSERT_VALUES_EQUAL(aa->RefCount(), 2);
  350. UNIT_ASSERT_VALUES_EQUAL(a->RefCount(), 2);
  351. aa.Reset();
  352. UNIT_ASSERT_VALUES_EQUAL(a->RefCount(), 1);
  353. // test that Func(TIntrusiveConstPtr<TB>) doesn't participate in overload resolution
  354. Func(aa);
  355. }
  356. void TPointerTest::TestMakeIntrusive() {
  357. {
  358. UNIT_ASSERT_VALUES_EQUAL(0, TOp::Cnt);
  359. auto p = MakeIntrusive<TOp>();
  360. UNIT_ASSERT_VALUES_EQUAL(1, p->RefCount());
  361. UNIT_ASSERT_VALUES_EQUAL(1, TOp::Cnt);
  362. }
  363. UNIT_ASSERT_VALUES_EQUAL(TOp::Cnt, 0);
  364. }
  365. void TPointerTest::TestCopyOnWritePtr1() {
  366. using TPtr = TCowPtr<TSimpleSharedPtr<int>>;
  367. TPtr p1;
  368. UNIT_ASSERT(!p1.Shared());
  369. p1.Reset(new int(123));
  370. UNIT_ASSERT(!p1.Shared());
  371. {
  372. TPtr pTmp = p1;
  373. UNIT_ASSERT(p1.Shared());
  374. UNIT_ASSERT(pTmp.Shared());
  375. UNIT_ASSERT_EQUAL(p1.Get(), pTmp.Get());
  376. }
  377. UNIT_ASSERT(!p1.Shared());
  378. TPtr p2 = p1;
  379. TPtr p3;
  380. p3 = p2;
  381. UNIT_ASSERT(p2.Shared());
  382. UNIT_ASSERT(p3.Shared());
  383. UNIT_ASSERT_EQUAL(p1.Get(), p2.Get());
  384. UNIT_ASSERT_EQUAL(p1.Get(), p3.Get());
  385. *(p1.Mutable()) = 456;
  386. UNIT_ASSERT(!p1.Shared());
  387. UNIT_ASSERT(p2.Shared());
  388. UNIT_ASSERT(p3.Shared());
  389. UNIT_ASSERT_EQUAL(*p1, 456);
  390. UNIT_ASSERT_EQUAL(*p2, 123);
  391. UNIT_ASSERT_EQUAL(*p3, 123);
  392. UNIT_ASSERT_UNEQUAL(p1.Get(), p2.Get());
  393. UNIT_ASSERT_EQUAL(p2.Get(), p3.Get());
  394. p2.Mutable();
  395. UNIT_ASSERT(!p2.Shared());
  396. UNIT_ASSERT(!p3.Shared());
  397. UNIT_ASSERT_EQUAL(*p2, 123);
  398. UNIT_ASSERT_EQUAL(*p3, 123);
  399. UNIT_ASSERT_UNEQUAL(p2.Get(), p3.Get());
  400. }
  401. struct X: public TSimpleRefCount<X> {
  402. inline X(int v = 0)
  403. : V(v)
  404. {
  405. }
  406. int V;
  407. };
  408. void TPointerTest::TestCopyOnWritePtr2() {
  409. using TPtr = TCowPtr<TIntrusivePtr<X>>;
  410. TPtr p1;
  411. UNIT_ASSERT(!p1.Shared());
  412. p1.Reset(new X(123));
  413. UNIT_ASSERT(!p1.Shared());
  414. {
  415. TPtr pTmp = p1;
  416. UNIT_ASSERT(p1.Shared());
  417. UNIT_ASSERT(pTmp.Shared());
  418. UNIT_ASSERT_EQUAL(p1.Get(), pTmp.Get());
  419. }
  420. UNIT_ASSERT(!p1.Shared());
  421. TPtr p2 = p1;
  422. TPtr p3;
  423. p3 = p2;
  424. UNIT_ASSERT(p2.Shared());
  425. UNIT_ASSERT(p3.Shared());
  426. UNIT_ASSERT_EQUAL(p1.Get(), p2.Get());
  427. UNIT_ASSERT_EQUAL(p1.Get(), p3.Get());
  428. p1.Mutable()->V = 456;
  429. UNIT_ASSERT(!p1.Shared());
  430. UNIT_ASSERT(p2.Shared());
  431. UNIT_ASSERT(p3.Shared());
  432. UNIT_ASSERT_EQUAL(p1->V, 456);
  433. UNIT_ASSERT_EQUAL(p2->V, 123);
  434. UNIT_ASSERT_EQUAL(p3->V, 123);
  435. UNIT_ASSERT_UNEQUAL(p1.Get(), p2.Get());
  436. UNIT_ASSERT_EQUAL(p2.Get(), p3.Get());
  437. p2.Mutable();
  438. UNIT_ASSERT(!p2.Shared());
  439. UNIT_ASSERT(!p3.Shared());
  440. UNIT_ASSERT_EQUAL(p2->V, 123);
  441. UNIT_ASSERT_EQUAL(p3->V, 123);
  442. UNIT_ASSERT_UNEQUAL(p2.Get(), p3.Get());
  443. }
  444. namespace {
  445. template <class TFrom, class TTo>
  446. struct TImplicitlyCastable {
  447. struct RTYes {
  448. char t[2];
  449. };
  450. using RTNo = char;
  451. static RTYes Func(TTo);
  452. static RTNo Func(...);
  453. static TFrom Get();
  454. /*
  455. * Result == (TFrom could be converted to TTo implicitly)
  456. */
  457. enum {
  458. Result = (sizeof(Func(Get())) != sizeof(RTNo))
  459. };
  460. };
  461. struct TImplicitlyCastableToBool {
  462. inline operator bool() const {
  463. return true;
  464. }
  465. };
  466. } // namespace
  467. void TPointerTest::TestOperatorBool() {
  468. using TVec = TVector<ui32>;
  469. // to be sure TImplicitlyCastable works as expected
  470. UNIT_ASSERT((TImplicitlyCastable<int, bool>::Result));
  471. UNIT_ASSERT((TImplicitlyCastable<double, int>::Result));
  472. UNIT_ASSERT((TImplicitlyCastable<int*, void*>::Result));
  473. UNIT_ASSERT(!(TImplicitlyCastable<void*, int*>::Result));
  474. UNIT_ASSERT((TImplicitlyCastable<TImplicitlyCastableToBool, bool>::Result));
  475. UNIT_ASSERT((TImplicitlyCastable<TImplicitlyCastableToBool, int>::Result));
  476. UNIT_ASSERT((TImplicitlyCastable<TImplicitlyCastableToBool, ui64>::Result));
  477. UNIT_ASSERT(!(TImplicitlyCastable<TImplicitlyCastableToBool, void*>::Result));
  478. // pointers
  479. UNIT_ASSERT(!(TImplicitlyCastable<TSimpleSharedPtr<TVec>, int>::Result));
  480. UNIT_ASSERT(!(TImplicitlyCastable<TAutoPtr<ui64>, ui64>::Result));
  481. UNIT_ASSERT(!(TImplicitlyCastable<THolder<TVec>, bool>::Result)); // even this
  482. {
  483. // mostly a compilability test
  484. THolder<TVec> a;
  485. UNIT_ASSERT(!a);
  486. UNIT_ASSERT(!bool(a));
  487. if (a) {
  488. UNIT_ASSERT(false);
  489. }
  490. if (!a) {
  491. UNIT_ASSERT(true);
  492. }
  493. a.Reset(new TVec);
  494. UNIT_ASSERT(a);
  495. UNIT_ASSERT(bool(a));
  496. if (a) {
  497. UNIT_ASSERT(true);
  498. }
  499. if (!a) {
  500. UNIT_ASSERT(false);
  501. }
  502. THolder<TVec> b(new TVec);
  503. UNIT_ASSERT(a.Get() != b.Get());
  504. UNIT_ASSERT(a != b);
  505. if (a == b) {
  506. UNIT_ASSERT(false);
  507. }
  508. if (a != b) {
  509. UNIT_ASSERT(true);
  510. }
  511. if (!(a && b)) {
  512. UNIT_ASSERT(false);
  513. }
  514. if (a && b) {
  515. UNIT_ASSERT(true);
  516. }
  517. // int i = a; // does not compile
  518. // bool c = (a < b); // does not compile
  519. }
  520. }
  521. void TPointerTest::TestMakeShared() {
  522. {
  523. TSimpleSharedPtr<int> ptr = MakeSimpleShared<int>(5);
  524. UNIT_ASSERT_VALUES_EQUAL(*ptr, 5);
  525. }
  526. {
  527. struct TRec {
  528. int X, Y;
  529. TRec()
  530. : X(1)
  531. , Y(2)
  532. {
  533. }
  534. };
  535. auto ptr = MakeAtomicShared<TRec>();
  536. UNIT_ASSERT_VALUES_EQUAL(ptr->X, 1);
  537. UNIT_ASSERT_VALUES_EQUAL(ptr->Y, 2);
  538. }
  539. {
  540. struct TRec {
  541. int X, Y;
  542. };
  543. TAtomicSharedPtr<TRec> ptr = MakeAtomicShared<TRec>(1, 2);
  544. UNIT_ASSERT_VALUES_EQUAL(ptr->X, 1);
  545. UNIT_ASSERT_VALUES_EQUAL(ptr->Y, 2);
  546. }
  547. {
  548. class TRec {
  549. private:
  550. int X_, Y_;
  551. public:
  552. TRec(int x, int y)
  553. : X_(x)
  554. , Y_(y)
  555. {
  556. }
  557. int GetX() const {
  558. return X_;
  559. }
  560. int GetY() const {
  561. return Y_;
  562. }
  563. };
  564. TSimpleSharedPtr<TRec> ptr = MakeSimpleShared<TRec>(1, 2);
  565. UNIT_ASSERT_VALUES_EQUAL(ptr->GetX(), 1);
  566. UNIT_ASSERT_VALUES_EQUAL(ptr->GetY(), 2);
  567. }
  568. {
  569. enum EObjectState {
  570. OS_NOT_CREATED,
  571. OS_CREATED,
  572. OS_DESTROYED,
  573. };
  574. struct TObject {
  575. EObjectState& State;
  576. TObject(EObjectState& state)
  577. : State(state)
  578. {
  579. State = OS_CREATED;
  580. }
  581. ~TObject() {
  582. State = OS_DESTROYED;
  583. }
  584. };
  585. auto throwsException = []() {
  586. throw yexception();
  587. return 5;
  588. };
  589. auto testFunction = [](TSimpleSharedPtr<TObject>, int) {
  590. };
  591. EObjectState state = OS_NOT_CREATED;
  592. try {
  593. testFunction(MakeSimpleShared<TObject>(state), throwsException());
  594. } catch (yexception&) {
  595. }
  596. UNIT_ASSERT(state == OS_NOT_CREATED || state == OS_DESTROYED);
  597. }
  598. }
  599. template <class TPtr>
  600. void TestPtrComparison(const TPtr& ptr) {
  601. UNIT_ASSERT(ptr == ptr);
  602. UNIT_ASSERT(!(ptr != ptr));
  603. UNIT_ASSERT(ptr == ptr.Get());
  604. UNIT_ASSERT(!(ptr != ptr.Get()));
  605. }
  606. void TPointerTest::TestComparison() {
  607. THolder<A> ptr1(new A);
  608. TAutoPtr<A> ptr2;
  609. TSimpleSharedPtr<int> ptr3(new int(6));
  610. TIntrusivePtr<A> ptr4;
  611. TIntrusiveConstPtr<A> ptr5 = ptr4;
  612. UNIT_ASSERT(ptr1 != nullptr);
  613. UNIT_ASSERT(ptr2 == nullptr);
  614. UNIT_ASSERT(ptr3 != nullptr);
  615. UNIT_ASSERT(ptr4 == nullptr);
  616. UNIT_ASSERT(ptr5 == nullptr);
  617. TestPtrComparison(ptr1);
  618. TestPtrComparison(ptr2);
  619. TestPtrComparison(ptr3);
  620. TestPtrComparison(ptr4);
  621. TestPtrComparison(ptr5);
  622. }
  623. template <class T, class TRefCountedPtr>
  624. void TPointerTest::TestRefCountedPtrsInHashSetImpl() {
  625. THashSet<TRefCountedPtr> hashSet;
  626. TRefCountedPtr p1(new T());
  627. UNIT_ASSERT(!IsIn(hashSet, p1));
  628. UNIT_ASSERT(hashSet.insert(p1).second);
  629. UNIT_ASSERT(IsIn(hashSet, p1));
  630. UNIT_ASSERT_VALUES_EQUAL(hashSet.size(), 1);
  631. UNIT_ASSERT(!hashSet.insert(p1).second);
  632. TRefCountedPtr p2(new T());
  633. UNIT_ASSERT(!IsIn(hashSet, p2));
  634. UNIT_ASSERT(hashSet.insert(p2).second);
  635. UNIT_ASSERT(IsIn(hashSet, p2));
  636. UNIT_ASSERT_VALUES_EQUAL(hashSet.size(), 2);
  637. }
  638. struct TCustomIntrusivePtrOps: TDefaultIntrusivePtrOps<A> {
  639. };
  640. struct TCustomDeleter: TDelete {
  641. };
  642. struct TCustomCounter: TSimpleCounter {
  643. using TSimpleCounterTemplate::TSimpleCounterTemplate;
  644. };
  645. void TPointerTest::TestRefCountedPtrsInHashSet() {
  646. // test common case
  647. TestRefCountedPtrsInHashSetImpl<TString, TSimpleSharedPtr<TString>>();
  648. TestRefCountedPtrsInHashSetImpl<TString, TAtomicSharedPtr<TString>>();
  649. TestRefCountedPtrsInHashSetImpl<A, TIntrusivePtr<A>>();
  650. TestRefCountedPtrsInHashSetImpl<A, TIntrusiveConstPtr<A>>();
  651. // test with custom ops
  652. TestRefCountedPtrsInHashSetImpl<TString, TSharedPtr<TString, TCustomCounter, TCustomDeleter>>();
  653. TestRefCountedPtrsInHashSetImpl<A, TIntrusivePtr<A, TCustomIntrusivePtrOps>>();
  654. TestRefCountedPtrsInHashSetImpl<A, TIntrusiveConstPtr<A, TCustomIntrusivePtrOps>>();
  655. }
  656. class TRefCountedWithStatistics: public TNonCopyable {
  657. public:
  658. struct TExternalCounter {
  659. std::atomic<size_t> Counter{0};
  660. std::atomic<size_t> Increments{0};
  661. };
  662. TRefCountedWithStatistics(TExternalCounter& cnt)
  663. : ExternalCounter_(cnt)
  664. {
  665. // Reset counters
  666. ExternalCounter_.Counter.store(0);
  667. ExternalCounter_.Increments.store(0);
  668. }
  669. void Ref() noexcept {
  670. ++ExternalCounter_.Counter;
  671. ++ExternalCounter_.Increments;
  672. }
  673. void UnRef() noexcept {
  674. if (--ExternalCounter_.Counter == 0) {
  675. TDelete::Destroy(this);
  676. }
  677. }
  678. void DecRef() noexcept {
  679. Y_ABORT_UNLESS(--ExternalCounter_.Counter != 0);
  680. }
  681. private:
  682. TExternalCounter& ExternalCounter_;
  683. };
  684. void TPointerTest::TestIntrusiveConstConstruction() {
  685. {
  686. TRefCountedWithStatistics::TExternalCounter cnt;
  687. UNIT_ASSERT_VALUES_EQUAL(cnt.Counter.load(), 0);
  688. UNIT_ASSERT_VALUES_EQUAL(cnt.Increments.load(), 0);
  689. TIntrusivePtr<TRefCountedWithStatistics> i{MakeIntrusive<TRefCountedWithStatistics>(cnt)};
  690. UNIT_ASSERT_VALUES_EQUAL(cnt.Counter.load(), 1);
  691. UNIT_ASSERT_VALUES_EQUAL(cnt.Increments.load(), 1);
  692. i.Reset();
  693. UNIT_ASSERT_VALUES_EQUAL(cnt.Counter.load(), 0);
  694. UNIT_ASSERT_VALUES_EQUAL(cnt.Increments.load(), 1);
  695. }
  696. {
  697. TRefCountedWithStatistics::TExternalCounter cnt;
  698. UNIT_ASSERT_VALUES_EQUAL(cnt.Counter.load(), 0);
  699. UNIT_ASSERT_VALUES_EQUAL(cnt.Increments.load(), 0);
  700. TIntrusiveConstPtr<TRefCountedWithStatistics> c{MakeIntrusive<TRefCountedWithStatistics>(cnt)};
  701. UNIT_ASSERT_VALUES_EQUAL(cnt.Counter.load(), 1);
  702. UNIT_ASSERT_VALUES_EQUAL(cnt.Increments.load(), 1);
  703. c.Reset();
  704. UNIT_ASSERT_VALUES_EQUAL(cnt.Counter.load(), 0);
  705. UNIT_ASSERT_VALUES_EQUAL(cnt.Increments.load(), 1);
  706. }
  707. }
  708. class TVirtualProbe: public NTesting::TProbe {
  709. public:
  710. using NTesting::TProbe::TProbe;
  711. virtual ~TVirtualProbe() = default;
  712. };
  713. class TDerivedProbe: public TVirtualProbe {
  714. public:
  715. using TVirtualProbe::TVirtualProbe;
  716. };
  717. class TDerivedProbeSibling: public TVirtualProbe {
  718. public:
  719. using TVirtualProbe::TVirtualProbe;
  720. };
  721. void TPointerTest::TestSharedPtrDowncast() {
  722. {
  723. NTesting::TProbeState probeState = {};
  724. {
  725. TSimpleSharedPtr<TVirtualProbe> base = MakeSimpleShared<TDerivedProbe>(&probeState);
  726. UNIT_ASSERT_VALUES_EQUAL(probeState.Constructors, 1);
  727. {
  728. auto derived = base.As<TDerivedProbe>();
  729. UNIT_ASSERT_VALUES_EQUAL(probeState.Constructors, 1);
  730. UNIT_ASSERT_VALUES_EQUAL(base.Get(), derived.Get());
  731. UNIT_ASSERT_VALUES_EQUAL(base.ReferenceCounter(), derived.ReferenceCounter());
  732. UNIT_ASSERT_VALUES_EQUAL(base.RefCount(), 2l);
  733. UNIT_ASSERT_VALUES_EQUAL(derived.RefCount(), 2l);
  734. }
  735. UNIT_ASSERT_VALUES_EQUAL(probeState.Destructors, 0);
  736. }
  737. UNIT_ASSERT_VALUES_EQUAL(probeState.Destructors, 1);
  738. }
  739. {
  740. NTesting::TProbeState probeState = {};
  741. {
  742. TSimpleSharedPtr<TVirtualProbe> base = MakeSimpleShared<TDerivedProbe>(&probeState);
  743. UNIT_ASSERT_VALUES_EQUAL(probeState.Constructors, 1);
  744. auto derived = std::move(base).As<TDerivedProbe>();
  745. UNIT_ASSERT_VALUES_EQUAL(probeState.Constructors, 1);
  746. UNIT_ASSERT_VALUES_EQUAL(probeState.CopyConstructors, 0);
  747. UNIT_ASSERT_VALUES_EQUAL(probeState.Destructors, 0);
  748. }
  749. UNIT_ASSERT_VALUES_EQUAL(probeState.Destructors, 1);
  750. }
  751. {
  752. NTesting::TProbeState probeState = {};
  753. {
  754. TSimpleSharedPtr<TVirtualProbe> base = MakeSimpleShared<TDerivedProbe>(&probeState);
  755. UNIT_ASSERT_VALUES_EQUAL(probeState.Constructors, 1);
  756. {
  757. auto derivedSibling = base.As<TDerivedProbeSibling>();
  758. UNIT_ASSERT_VALUES_EQUAL(probeState.Constructors, 1);
  759. UNIT_ASSERT_VALUES_EQUAL(derivedSibling.Get(), nullptr);
  760. UNIT_ASSERT_VALUES_UNEQUAL(base.ReferenceCounter(), derivedSibling.ReferenceCounter());
  761. UNIT_ASSERT_VALUES_EQUAL(base.RefCount(), 1l);
  762. UNIT_ASSERT_VALUES_EQUAL(derivedSibling.RefCount(), 0l);
  763. }
  764. UNIT_ASSERT_VALUES_EQUAL(probeState.Destructors, 0);
  765. }
  766. UNIT_ASSERT_VALUES_EQUAL(probeState.Destructors, 1);
  767. }
  768. {
  769. NTesting::TProbeState probeState = {};
  770. {
  771. TSimpleSharedPtr<TVirtualProbe> base = MakeSimpleShared<TDerivedProbe>(&probeState);
  772. UNIT_ASSERT_VALUES_EQUAL(probeState.Constructors, 1);
  773. auto derived = std::move(base).As<TDerivedProbeSibling>();
  774. UNIT_ASSERT_VALUES_EQUAL(derived.Get(), nullptr);
  775. UNIT_ASSERT_VALUES_EQUAL(probeState.Constructors, 1);
  776. UNIT_ASSERT_VALUES_EQUAL(probeState.CopyConstructors, 0);
  777. UNIT_ASSERT_VALUES_EQUAL(probeState.Destructors, 0);
  778. }
  779. UNIT_ASSERT_VALUES_EQUAL(probeState.Destructors, 1);
  780. }
  781. }
  782. void TPointerTest::TestStdCompatibility() {
  783. {
  784. TSimpleSharedPtr<int> ptr = MakeSimpleShared<int>(5);
  785. UNIT_ASSERT_TYPES_EQUAL(decltype(ptr)::element_type, int);
  786. UNIT_ASSERT_VALUES_EQUAL(ptr.get(), ptr.Get());
  787. }
  788. {
  789. TAtomicSharedPtr<int> ptr = MakeAtomicShared<int>(5);
  790. UNIT_ASSERT_TYPES_EQUAL(decltype(ptr)::element_type, int);
  791. UNIT_ASSERT_VALUES_EQUAL(ptr.get(), ptr.Get());
  792. }
  793. {
  794. TAutoPtr<int> ptr = MakeHolder<int>(5);
  795. UNIT_ASSERT_TYPES_EQUAL(decltype(ptr)::element_type, int);
  796. UNIT_ASSERT_VALUES_EQUAL(ptr.get(), ptr.Get());
  797. }
  798. {
  799. TIntrusivePtr<TOp> ptr;
  800. UNIT_ASSERT_TYPES_EQUAL(decltype(ptr)::element_type, TOp);
  801. UNIT_ASSERT_VALUES_EQUAL(ptr.get(), ptr.Get());
  802. }
  803. }