ptr.h 25 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174
  1. #pragma once
  2. #include "fwd.h"
  3. #include "utility.h"
  4. #include "intrlist.h"
  5. #include "refcount.h"
  6. #include "typetraits.h"
  7. #include "singleton.h"
  8. #include <type_traits>
  9. #include <utility>
  10. #include <util/system/compiler.h>
  11. #include <util/system/defaults.h>
  12. #include <util/system/yassert.h>
  13. template <class T, class U>
  14. using TGuardConversion = typename std::enable_if_t<std::is_convertible<U*, T*>::value>;
  15. template <class T>
  16. inline void AssertTypeComplete() {
  17. // If compiler triggers this error from destructor of your class with
  18. // smart pointer, then may be you should move the destructor definition
  19. // to the .cpp file, where type T have full definition.
  20. //
  21. // 'delete' called on pointer to incomplete type is
  22. // undefined behavior (missing destructor call/corrupted memory manager).
  23. // 'sizeof' is used to trigger compile-time error.
  24. static_assert(sizeof(T) != 0, "Type must be complete");
  25. }
  26. template <class T>
  27. inline void CheckedDelete(T* t) {
  28. AssertTypeComplete<T>();
  29. delete t;
  30. }
  31. template <class T>
  32. inline void CheckedArrayDelete(T* t) {
  33. AssertTypeComplete<T>();
  34. delete[] t;
  35. }
  36. class TNoAction {
  37. public:
  38. template <class T>
  39. static inline void Destroy(T*) noexcept {
  40. }
  41. };
  42. class TDelete {
  43. public:
  44. template <class T>
  45. static inline void Destroy(T* t) noexcept {
  46. CheckedDelete(t);
  47. }
  48. /*
  49. * special handling for nullptr - call nothing
  50. */
  51. static inline void Destroy(std::nullptr_t) noexcept {
  52. }
  53. /*
  54. * special handling for void* - call ::operator delete()
  55. */
  56. static void Destroy(void* t) noexcept;
  57. };
  58. class TDeleteArray {
  59. public:
  60. template <class T>
  61. static inline void Destroy(T* t) noexcept {
  62. CheckedArrayDelete(t);
  63. }
  64. };
  65. class TDestructor {
  66. public:
  67. template <class T>
  68. static inline void Destroy(T* t) noexcept {
  69. (void)t;
  70. t->~T();
  71. }
  72. };
  73. class TFree {
  74. public:
  75. template <class T>
  76. static inline void Destroy(T* t) noexcept {
  77. DoDestroy((void*)t);
  78. }
  79. private:
  80. /*
  81. * we do not want dependancy on cstdlib here...
  82. */
  83. static void DoDestroy(void* t) noexcept;
  84. };
  85. template <class Base, class T>
  86. class TPointerCommon {
  87. public:
  88. using TValueType = T;
  89. inline T* operator->() const noexcept {
  90. T* ptr = AsT();
  91. Y_ASSERT(ptr);
  92. return ptr;
  93. }
  94. #ifndef __cpp_impl_three_way_comparison
  95. template <class C>
  96. inline bool operator==(const C& p) const noexcept {
  97. return (p == AsT());
  98. }
  99. template <class C>
  100. inline bool operator!=(const C& p) const noexcept {
  101. return (p != AsT());
  102. }
  103. #endif
  104. inline explicit operator bool() const noexcept {
  105. return nullptr != AsT();
  106. }
  107. protected:
  108. inline T* AsT() const noexcept {
  109. return (static_cast<const Base*>(this))->Get();
  110. }
  111. static inline T* DoRelease(T*& t) noexcept {
  112. T* ret = t;
  113. t = nullptr;
  114. return ret;
  115. }
  116. };
  117. template <class Base, class T>
  118. class TPointerBase: public TPointerCommon<Base, T> {
  119. public:
  120. inline T& operator*() const noexcept {
  121. Y_ASSERT(this->AsT());
  122. return *(this->AsT());
  123. }
  124. inline T& operator[](size_t n) const noexcept {
  125. Y_ASSERT(this->AsT());
  126. return (this->AsT())[n];
  127. }
  128. };
  129. /*
  130. * void*-like pointers does not have operator*
  131. */
  132. template <class Base>
  133. class TPointerBase<Base, void>: public TPointerCommon<Base, void> {
  134. };
  135. template <class T, class D>
  136. class TAutoPtr: public TPointerBase<TAutoPtr<T, D>, T> {
  137. public:
  138. inline TAutoPtr(T* t = nullptr) noexcept
  139. : T_(t)
  140. {
  141. }
  142. inline TAutoPtr(const TAutoPtr& t) noexcept
  143. : T_(t.Release())
  144. {
  145. }
  146. inline ~TAutoPtr() {
  147. DoDestroy();
  148. }
  149. inline TAutoPtr& operator=(const TAutoPtr& t) noexcept {
  150. if (this != &t) {
  151. Reset(t.Release());
  152. }
  153. return *this;
  154. }
  155. inline T* Release() const noexcept Y_WARN_UNUSED_RESULT {
  156. return this->DoRelease(T_);
  157. }
  158. Y_REINITIALIZES_OBJECT inline void Reset(T* t) noexcept {
  159. if (T_ != t) {
  160. DoDestroy();
  161. T_ = t;
  162. }
  163. }
  164. Y_REINITIALIZES_OBJECT inline void Reset() noexcept {
  165. Destroy();
  166. }
  167. inline void Destroy() noexcept {
  168. Reset(nullptr);
  169. }
  170. inline void Swap(TAutoPtr& r) noexcept {
  171. DoSwap(T_, r.T_);
  172. }
  173. inline T* Get() const noexcept {
  174. return T_;
  175. }
  176. #ifdef __cpp_impl_three_way_comparison
  177. template <class Other>
  178. inline bool operator==(const Other& p) const noexcept {
  179. return (p == Get());
  180. }
  181. #endif
  182. private:
  183. inline void DoDestroy() noexcept {
  184. if (T_) {
  185. D::Destroy(T_);
  186. }
  187. }
  188. private:
  189. mutable T* T_;
  190. };
  191. template <class T, class D>
  192. class THolder: public TPointerBase<THolder<T, D>, T> {
  193. public:
  194. constexpr THolder() noexcept
  195. : T_(nullptr)
  196. {
  197. }
  198. constexpr THolder(std::nullptr_t) noexcept
  199. : T_(nullptr)
  200. {
  201. }
  202. explicit THolder(T* t) noexcept
  203. : T_(t)
  204. {
  205. }
  206. inline THolder(TAutoPtr<T, D> t) noexcept
  207. : T_(t.Release())
  208. {
  209. }
  210. template <class U, class = TGuardConversion<T, U>>
  211. inline THolder(TAutoPtr<U, D> t) noexcept
  212. : T_(t.Release())
  213. {
  214. }
  215. inline THolder(THolder&& that) noexcept
  216. : T_(that.Release())
  217. {
  218. }
  219. template <class U, class = TGuardConversion<T, U>>
  220. inline THolder(THolder<U, D>&& that) noexcept
  221. : T_(that.Release())
  222. {
  223. }
  224. THolder(const THolder&) = delete;
  225. THolder& operator=(const THolder&) = delete;
  226. inline ~THolder() {
  227. DoDestroy();
  228. }
  229. inline void Destroy() noexcept {
  230. Reset(nullptr);
  231. }
  232. inline T* Release() noexcept Y_WARN_UNUSED_RESULT {
  233. return this->DoRelease(T_);
  234. }
  235. Y_REINITIALIZES_OBJECT inline void Reset(T* t) noexcept {
  236. if (T_ != t) {
  237. DoDestroy();
  238. T_ = t;
  239. }
  240. }
  241. Y_REINITIALIZES_OBJECT inline void Reset(TAutoPtr<T, D> t) noexcept {
  242. Reset(t.Release());
  243. }
  244. Y_REINITIALIZES_OBJECT inline void Reset() noexcept {
  245. Destroy();
  246. }
  247. inline void Swap(THolder& r) noexcept {
  248. DoSwap(T_, r.T_);
  249. }
  250. inline T* Get() const noexcept {
  251. return T_;
  252. }
  253. inline operator TAutoPtr<T, D>() noexcept {
  254. return Release();
  255. }
  256. THolder& operator=(std::nullptr_t) noexcept {
  257. this->Reset(nullptr);
  258. return *this;
  259. }
  260. THolder& operator=(THolder&& that) noexcept {
  261. this->Reset(that.Release());
  262. return *this;
  263. }
  264. template <class U>
  265. THolder& operator=(THolder<U, D>&& that) noexcept {
  266. this->Reset(that.Release());
  267. return *this;
  268. }
  269. #ifdef __cpp_impl_three_way_comparison
  270. template <class Other>
  271. inline bool operator==(const Other& p) const noexcept {
  272. return (p == Get());
  273. }
  274. #endif
  275. private:
  276. inline void DoDestroy() noexcept {
  277. if (T_) {
  278. D::Destroy(T_);
  279. }
  280. }
  281. private:
  282. T* T_;
  283. };
  284. template <typename T, typename... Args>
  285. [[nodiscard]] THolder<T> MakeHolder(Args&&... args) {
  286. return THolder<T>(new T(std::forward<Args>(args)...));
  287. }
  288. /*
  289. * usage:
  290. * class T: public TRefCounted<T>
  291. * and we get methods Ref() && UnRef() with
  292. * proper destruction of last UnRef()
  293. */
  294. template <class T, class C, class D>
  295. class TRefCounted {
  296. public:
  297. inline TRefCounted(long initval = 0) noexcept
  298. : Counter_(initval)
  299. {
  300. }
  301. inline ~TRefCounted() = default;
  302. inline void Ref(intptr_t d) noexcept {
  303. auto resultCount = Counter_.Add(d);
  304. Y_ASSERT(resultCount >= d);
  305. (void)resultCount;
  306. }
  307. inline void Ref() noexcept {
  308. auto resultCount = Counter_.Inc();
  309. Y_ASSERT(resultCount != 0);
  310. (void)resultCount;
  311. }
  312. inline void UnRef(intptr_t d) noexcept {
  313. auto resultCount = Counter_.Sub(d);
  314. Y_ASSERT(resultCount >= 0);
  315. if (resultCount == 0) {
  316. D::Destroy(static_cast<T*>(this));
  317. }
  318. }
  319. inline void UnRef() noexcept {
  320. UnRef(1);
  321. }
  322. inline intptr_t RefCount() const noexcept {
  323. return Counter_.Val();
  324. }
  325. inline void DecRef() noexcept {
  326. auto resultCount = Counter_.Dec();
  327. Y_ASSERT(resultCount >= 0);
  328. (void)resultCount;
  329. }
  330. TRefCounted(const TRefCounted&)
  331. : Counter_(0)
  332. {
  333. }
  334. void operator=(const TRefCounted&) {
  335. }
  336. private:
  337. C Counter_;
  338. };
  339. /**
  340. * Atomically reference-counted base with a virtual destructor.
  341. *
  342. * @note Plays well with inheritance, should be used for refcounted base classes.
  343. */
  344. struct TThrRefBase: public TRefCounted<TThrRefBase, TAtomicCounter> {
  345. virtual ~TThrRefBase();
  346. };
  347. /**
  348. * Atomically reference-counted base.
  349. *
  350. * Deletes refcounted object as type T.
  351. *
  352. * @warning Additional care should be taken with regard to inheritance. If used
  353. * as a base class, @p T should either declare a virtual destructor, or be
  354. * derived from @p TThrRefBase instead. Otherwise, only destructor of class @p T
  355. * would be called, potentially slicing the object and creating memory leaks.
  356. *
  357. * @note To avoid accidental inheritance when it is not originally intended,
  358. * class @p T should be marked as final.
  359. */
  360. template <class T, class D = TDelete>
  361. using TAtomicRefCount = TRefCounted<T, TAtomicCounter, D>;
  362. /**
  363. * Non-atomically reference-counted base.
  364. *
  365. * @warning Not thread-safe. Use with great care. If in doubt, use @p ThrRefBase
  366. * or @p TAtomicRefCount instead.
  367. */
  368. template <class T, class D = TDelete>
  369. using TSimpleRefCount = TRefCounted<T, TSimpleCounter, D>;
  370. template <class T>
  371. class TDefaultIntrusivePtrOps {
  372. public:
  373. static inline void Ref(T* t) noexcept {
  374. Y_ASSERT(t);
  375. t->Ref();
  376. }
  377. static inline void UnRef(T* t) noexcept {
  378. Y_ASSERT(t);
  379. t->UnRef();
  380. }
  381. static inline void DecRef(T* t) noexcept {
  382. Y_ASSERT(t);
  383. t->DecRef();
  384. }
  385. static inline long RefCount(const T* t) noexcept {
  386. Y_ASSERT(t);
  387. return t->RefCount();
  388. }
  389. };
  390. template <class T, class Ops>
  391. class TIntrusivePtr: public TPointerBase<TIntrusivePtr<T, Ops>, T> {
  392. template <class U, class O>
  393. friend class TIntrusivePtr;
  394. template <class U, class O>
  395. friend class TIntrusiveConstPtr;
  396. public:
  397. struct TNoIncrement {
  398. };
  399. inline TIntrusivePtr(T* t = nullptr) noexcept
  400. : T_(t)
  401. {
  402. Ops();
  403. Ref();
  404. }
  405. inline TIntrusivePtr(T* t, TNoIncrement) noexcept
  406. : T_(t)
  407. {
  408. Ops();
  409. }
  410. inline ~TIntrusivePtr() {
  411. UnRef();
  412. }
  413. inline TIntrusivePtr(const TIntrusivePtr& p) noexcept
  414. : T_(p.T_)
  415. {
  416. Ref();
  417. }
  418. // NOTE:
  419. // without std::enable_if_t compiler sometimes tries to use this constructor inappropriately
  420. // e.g.
  421. // struct A {};
  422. // struct B {};
  423. // void Func(TIntrusivePtr<A>);
  424. // void Func(TIntrusivePtr<B>);
  425. // ...
  426. // Func(TIntrusivePtr<A>(new A)); // <--- compiler can't decide which version of Func to use
  427. template <class U, class = TGuardConversion<T, U>>
  428. inline TIntrusivePtr(const TIntrusivePtr<U>& p) noexcept
  429. : T_(p.Get())
  430. {
  431. Ref();
  432. }
  433. template <class U, class = TGuardConversion<T, U>>
  434. inline TIntrusivePtr(TIntrusivePtr<U>&& p) noexcept
  435. : T_(p.T_)
  436. {
  437. p.T_ = nullptr;
  438. }
  439. inline TIntrusivePtr(TIntrusivePtr&& p) noexcept
  440. : T_(nullptr)
  441. {
  442. Swap(p);
  443. }
  444. inline TIntrusivePtr& operator=(TIntrusivePtr p) noexcept {
  445. p.Swap(*this);
  446. return *this;
  447. }
  448. // Effectively replace both:
  449. // Reset(const TIntrusivePtr&)
  450. // Reset(TIntrusivePtr&&)
  451. Y_REINITIALIZES_OBJECT inline void Reset(TIntrusivePtr t) noexcept {
  452. Swap(t);
  453. }
  454. Y_REINITIALIZES_OBJECT inline void Reset() noexcept {
  455. Drop();
  456. }
  457. inline T* Get() const noexcept {
  458. return T_;
  459. }
  460. inline void Swap(TIntrusivePtr& r) noexcept {
  461. DoSwap(T_, r.T_);
  462. }
  463. inline void Drop() noexcept {
  464. TIntrusivePtr(nullptr).Swap(*this);
  465. }
  466. inline T* Release() const noexcept Y_WARN_UNUSED_RESULT {
  467. T* res = T_;
  468. if (T_) {
  469. Ops::DecRef(T_);
  470. T_ = nullptr;
  471. }
  472. return res;
  473. }
  474. inline long RefCount() const noexcept {
  475. return T_ ? Ops::RefCount(T_) : 0;
  476. }
  477. #ifdef __cpp_impl_three_way_comparison
  478. template <class Other>
  479. inline bool operator==(const Other& p) const noexcept {
  480. return (p == Get());
  481. }
  482. #endif
  483. private:
  484. inline void Ref() noexcept {
  485. if (T_) {
  486. Ops::Ref(T_);
  487. }
  488. }
  489. inline void UnRef() noexcept {
  490. if (T_) {
  491. Ops::UnRef(T_);
  492. }
  493. }
  494. private:
  495. mutable T* T_;
  496. };
  497. template <class T, class Ops>
  498. struct THash<TIntrusivePtr<T, Ops>>: THash<const T*> {
  499. using THash<const T*>::operator();
  500. inline size_t operator()(const TIntrusivePtr<T, Ops>& ptr) const {
  501. return THash<const T*>::operator()(ptr.Get());
  502. }
  503. };
  504. // Behaves like TIntrusivePtr but returns const T* to prevent user from accidentally modifying the referenced object.
  505. template <class T, class Ops>
  506. class TIntrusiveConstPtr: public TPointerBase<TIntrusiveConstPtr<T, Ops>, const T> {
  507. public:
  508. inline TIntrusiveConstPtr(T* t = nullptr) noexcept // we need a non-const pointer to Ref(), UnRef() and eventually delete it.
  509. : T_(t)
  510. {
  511. Ops();
  512. Ref();
  513. }
  514. inline ~TIntrusiveConstPtr() {
  515. UnRef();
  516. }
  517. inline TIntrusiveConstPtr(const TIntrusiveConstPtr& p) noexcept
  518. : T_(p.T_)
  519. {
  520. Ref();
  521. }
  522. inline TIntrusiveConstPtr(TIntrusiveConstPtr&& p) noexcept
  523. : T_(nullptr)
  524. {
  525. Swap(p);
  526. }
  527. inline TIntrusiveConstPtr(TIntrusivePtr<T> p) noexcept
  528. : T_(p.T_)
  529. {
  530. p.T_ = nullptr;
  531. }
  532. template <class U, class = TGuardConversion<T, U>>
  533. inline TIntrusiveConstPtr(const TIntrusiveConstPtr<U>& p) noexcept
  534. : T_(p.T_)
  535. {
  536. Ref();
  537. }
  538. template <class U, class = TGuardConversion<T, U>>
  539. inline TIntrusiveConstPtr(TIntrusiveConstPtr<U>&& p) noexcept
  540. : T_(p.T_)
  541. {
  542. p.T_ = nullptr;
  543. }
  544. inline TIntrusiveConstPtr& operator=(TIntrusiveConstPtr p) noexcept {
  545. p.Swap(*this);
  546. return *this;
  547. }
  548. // Effectively replace both:
  549. // Reset(const TIntrusiveConstPtr&)
  550. // Reset(TIntrusiveConstPtr&&)
  551. Y_REINITIALIZES_OBJECT inline void Reset(TIntrusiveConstPtr t) noexcept {
  552. Swap(t);
  553. }
  554. Y_REINITIALIZES_OBJECT inline void Reset() noexcept {
  555. Drop();
  556. }
  557. inline const T* Get() const noexcept {
  558. return T_;
  559. }
  560. inline void Swap(TIntrusiveConstPtr& r) noexcept {
  561. DoSwap(T_, r.T_);
  562. }
  563. inline void Drop() noexcept {
  564. TIntrusiveConstPtr(nullptr).Swap(*this);
  565. }
  566. inline long RefCount() const noexcept {
  567. return T_ ? Ops::RefCount(T_) : 0;
  568. }
  569. #ifdef __cpp_impl_three_way_comparison
  570. template <class Other>
  571. inline bool operator==(const Other& p) const noexcept {
  572. return (p == Get());
  573. }
  574. #endif
  575. private:
  576. inline void Ref() noexcept {
  577. if (T_ != nullptr) {
  578. Ops::Ref(T_);
  579. }
  580. }
  581. inline void UnRef() noexcept {
  582. if (T_ != nullptr) {
  583. Ops::UnRef(T_);
  584. }
  585. }
  586. private:
  587. T* T_;
  588. template <class U, class O>
  589. friend class TIntrusiveConstPtr;
  590. };
  591. template <class T, class Ops>
  592. struct THash<TIntrusiveConstPtr<T, Ops>>: THash<const T*> {
  593. using THash<const T*>::operator();
  594. inline size_t operator()(const TIntrusiveConstPtr<T, Ops>& ptr) const {
  595. return THash<const T*>::operator()(ptr.Get());
  596. }
  597. };
  598. template <class T, class Ops>
  599. class TSimpleIntrusiveOps {
  600. using TFunc = void (*)(T*)
  601. #if __cplusplus >= 201703
  602. noexcept
  603. #endif
  604. ;
  605. static void DoRef(T* t) noexcept {
  606. Ops::Ref(t);
  607. }
  608. static void DoUnRef(T* t) noexcept {
  609. Ops::UnRef(t);
  610. }
  611. public:
  612. inline TSimpleIntrusiveOps() noexcept {
  613. InitStaticOps();
  614. }
  615. inline ~TSimpleIntrusiveOps() = default;
  616. static inline void Ref(T* t) noexcept {
  617. Ref_(t);
  618. }
  619. static inline void UnRef(T* t) noexcept {
  620. UnRef_(t);
  621. }
  622. private:
  623. static inline void InitStaticOps() noexcept {
  624. struct TInit {
  625. inline TInit() noexcept {
  626. Ref_ = DoRef;
  627. UnRef_ = DoUnRef;
  628. }
  629. };
  630. Singleton<TInit>();
  631. }
  632. private:
  633. static TFunc Ref_;
  634. static TFunc UnRef_;
  635. };
  636. template <class T, class Ops>
  637. typename TSimpleIntrusiveOps<T, Ops>::TFunc TSimpleIntrusiveOps<T, Ops>::Ref_ = nullptr;
  638. template <class T, class Ops>
  639. typename TSimpleIntrusiveOps<T, Ops>::TFunc TSimpleIntrusiveOps<T, Ops>::UnRef_ = nullptr;
  640. template <typename T, class Ops = TDefaultIntrusivePtrOps<T>, typename... Args>
  641. [[nodiscard]] TIntrusivePtr<T, Ops> MakeIntrusive(Args&&... args) {
  642. return new T{std::forward<Args>(args)...};
  643. }
  644. template <typename T, class Ops = TDefaultIntrusivePtrOps<T>, typename... Args>
  645. [[nodiscard]] TIntrusiveConstPtr<T, Ops> MakeIntrusiveConst(Args&&... args) {
  646. return new T{std::forward<Args>(args)...};
  647. }
  648. template <class T, class C, class D>
  649. class TSharedPtr: public TPointerBase<TSharedPtr<T, C, D>, T> {
  650. template <class TT, class CC, class DD>
  651. friend class TSharedPtr;
  652. public:
  653. inline TSharedPtr() noexcept
  654. : T_(nullptr)
  655. , C_(nullptr)
  656. {
  657. }
  658. inline TSharedPtr(T* t) {
  659. THolder<T, D> h(t);
  660. Init(h);
  661. }
  662. inline TSharedPtr(TAutoPtr<T, D> t) {
  663. Init(t);
  664. }
  665. inline TSharedPtr(T* t, C* c) noexcept
  666. : T_(t)
  667. , C_(c)
  668. {
  669. }
  670. template <class TT, class = TGuardConversion<T, TT>>
  671. inline TSharedPtr(THolder<TT>&& t) {
  672. Init(t);
  673. }
  674. inline ~TSharedPtr() {
  675. UnRef();
  676. }
  677. inline TSharedPtr(const TSharedPtr& t) noexcept
  678. : T_(t.T_)
  679. , C_(t.C_)
  680. {
  681. Ref();
  682. }
  683. inline TSharedPtr(TSharedPtr&& t) noexcept
  684. : T_(nullptr)
  685. , C_(nullptr)
  686. {
  687. Swap(t);
  688. }
  689. template <class TT, class = TGuardConversion<T, TT>>
  690. inline TSharedPtr(const TSharedPtr<TT, C, D>& t) noexcept
  691. : T_(t.T_)
  692. , C_(t.C_)
  693. {
  694. Ref();
  695. }
  696. template <class TT, class = TGuardConversion<T, TT>>
  697. inline TSharedPtr(TSharedPtr<TT, C, D>&& t) noexcept
  698. : T_(t.T_)
  699. , C_(t.C_)
  700. {
  701. t.T_ = nullptr;
  702. t.C_ = nullptr;
  703. }
  704. inline TSharedPtr& operator=(TSharedPtr t) noexcept {
  705. t.Swap(*this);
  706. return *this;
  707. }
  708. // Effectively replace both:
  709. // Reset(const TSharedPtr& t)
  710. // Reset(TSharedPtr&& t)
  711. Y_REINITIALIZES_OBJECT inline void Reset(TSharedPtr t) noexcept {
  712. Swap(t);
  713. }
  714. Y_REINITIALIZES_OBJECT inline void Reset() noexcept {
  715. Drop();
  716. }
  717. inline void Drop() noexcept {
  718. TSharedPtr().Swap(*this);
  719. }
  720. inline T* Get() const noexcept {
  721. return T_;
  722. }
  723. inline C* ReferenceCounter() const noexcept {
  724. return C_;
  725. }
  726. inline void Swap(TSharedPtr& r) noexcept {
  727. DoSwap(T_, r.T_);
  728. DoSwap(C_, r.C_);
  729. }
  730. inline long RefCount() const noexcept {
  731. return C_ ? C_->Val() : 0;
  732. }
  733. template <class TT>
  734. [[nodiscard]] inline TSharedPtr<TT, C, D> As() & noexcept {
  735. static_assert(std::has_virtual_destructor<TT>(), "Type should have a virtual dtor");
  736. static_assert(std::is_base_of<T, TT>(), "When downcasting from T to TT, T should be a parent of TT");
  737. if (const auto ttPtr = dynamic_cast<TT*>(T_)) {
  738. TSharedPtr<TT, C, D> ttSharedPtr(ttPtr, C_);
  739. ttSharedPtr.Ref();
  740. return ttSharedPtr;
  741. } else {
  742. return TSharedPtr<TT, C, D>{};
  743. }
  744. }
  745. template <class TT>
  746. [[nodiscard]] inline TSharedPtr<TT, C, D> As() && noexcept {
  747. static_assert(std::has_virtual_destructor<TT>(), "Type should have a virtual dtor");
  748. static_assert(std::is_base_of<T, TT>(), "When downcasting from T to TT, T should be a parent of TT");
  749. if (const auto ttPtr = dynamic_cast<TT*>(T_)) {
  750. TSharedPtr<TT, C, D> ttSharedPtr(ttPtr, C_);
  751. T_ = nullptr;
  752. C_ = nullptr;
  753. return ttSharedPtr;
  754. } else {
  755. return TSharedPtr<TT, C, D>{};
  756. }
  757. }
  758. #ifdef __cpp_impl_three_way_comparison
  759. template <class Other>
  760. inline bool operator==(const Other& p) const noexcept {
  761. return (p == Get());
  762. }
  763. #endif
  764. private:
  765. template <class X>
  766. inline void Init(X& t) {
  767. C_ = !!t ? new C(1) : nullptr;
  768. T_ = t.Release();
  769. }
  770. inline void Ref() noexcept {
  771. if (C_) {
  772. C_->Inc();
  773. }
  774. }
  775. inline void UnRef() noexcept {
  776. if (C_ && !C_->Dec()) {
  777. DoDestroy();
  778. }
  779. }
  780. inline void DoDestroy() noexcept {
  781. if (T_) {
  782. D::Destroy(T_);
  783. }
  784. delete C_;
  785. }
  786. private:
  787. T* T_;
  788. C* C_;
  789. };
  790. template <class T, class C, class D>
  791. struct THash<TSharedPtr<T, C, D>>: THash<const T*> {
  792. using THash<const T*>::operator();
  793. inline size_t operator()(const TSharedPtr<T, C, D>& ptr) const {
  794. return THash<const T*>::operator()(ptr.Get());
  795. }
  796. };
  797. template <class T, class D = TDelete>
  798. using TAtomicSharedPtr = TSharedPtr<T, TAtomicCounter, D>;
  799. // use with great care. if in doubt, use TAtomicSharedPtr instead
  800. template <class T, class D = TDelete>
  801. using TSimpleSharedPtr = TSharedPtr<T, TSimpleCounter, D>;
  802. template <typename T, typename C, typename... Args>
  803. [[nodiscard]] TSharedPtr<T, C> MakeShared(Args&&... args) {
  804. return new T{std::forward<Args>(args)...};
  805. }
  806. template <typename T, typename... Args>
  807. [[nodiscard]] inline TAtomicSharedPtr<T> MakeAtomicShared(Args&&... args) {
  808. return MakeShared<T, TAtomicCounter>(std::forward<Args>(args)...);
  809. }
  810. template <typename T, typename... Args>
  811. [[nodiscard]] inline TSimpleSharedPtr<T> MakeSimpleShared(Args&&... args) {
  812. return MakeShared<T, TSimpleCounter>(std::forward<Args>(args)...);
  813. }
  814. class TCopyClone {
  815. public:
  816. template <class T>
  817. static inline T* Copy(T* t) {
  818. if (t)
  819. return t->Clone();
  820. return nullptr;
  821. }
  822. };
  823. class TCopyNew {
  824. public:
  825. template <class T>
  826. static inline T* Copy(T* t) {
  827. if (t)
  828. return new T(*t);
  829. return nullptr;
  830. }
  831. };
  832. template <class T, class C, class D>
  833. class TCopyPtr: public TPointerBase<TCopyPtr<T, C, D>, T> {
  834. public:
  835. inline TCopyPtr(T* t = nullptr) noexcept
  836. : T_(t)
  837. {
  838. }
  839. inline TCopyPtr(const TCopyPtr& t)
  840. : T_(C::Copy(t.Get()))
  841. {
  842. }
  843. inline TCopyPtr(TCopyPtr&& t) noexcept
  844. : T_(nullptr)
  845. {
  846. Swap(t);
  847. }
  848. inline ~TCopyPtr() {
  849. DoDestroy();
  850. }
  851. inline TCopyPtr& operator=(TCopyPtr t) noexcept {
  852. t.Swap(*this);
  853. return *this;
  854. }
  855. inline T* Release() noexcept Y_WARN_UNUSED_RESULT {
  856. return DoRelease(T_);
  857. }
  858. Y_REINITIALIZES_OBJECT inline void Reset(T* t) noexcept {
  859. if (T_ != t) {
  860. DoDestroy();
  861. T_ = t;
  862. }
  863. }
  864. Y_REINITIALIZES_OBJECT inline void Reset() noexcept {
  865. Destroy();
  866. }
  867. inline void Destroy() noexcept {
  868. Reset(nullptr);
  869. }
  870. inline void Swap(TCopyPtr& r) noexcept {
  871. DoSwap(T_, r.T_);
  872. }
  873. inline T* Get() const noexcept {
  874. return T_;
  875. }
  876. #ifdef __cpp_impl_three_way_comparison
  877. template <class Other>
  878. inline bool operator==(const Other& p) const noexcept {
  879. return (p == Get());
  880. }
  881. #endif
  882. private:
  883. inline void DoDestroy() noexcept {
  884. if (T_)
  885. D::Destroy(T_);
  886. }
  887. private:
  888. T* T_;
  889. };
  890. // Copy-on-write pointer
  891. template <class TPtr, class TCopy>
  892. class TCowPtr: public TPointerBase<TCowPtr<TPtr, TCopy>, const typename TPtr::TValueType> {
  893. using T = typename TPtr::TValueType;
  894. public:
  895. inline TCowPtr() = default;
  896. inline TCowPtr(const TPtr& p)
  897. : T_(p)
  898. {
  899. }
  900. inline TCowPtr(T* p)
  901. : T_(p)
  902. {
  903. }
  904. inline const T* Get() const noexcept {
  905. return Const();
  906. }
  907. inline const T* Const() const noexcept {
  908. return T_.Get();
  909. }
  910. inline T* Mutable() {
  911. Unshare();
  912. return T_.Get();
  913. }
  914. inline bool Shared() const noexcept {
  915. return T_.RefCount() > 1;
  916. }
  917. inline void Swap(TCowPtr& r) noexcept {
  918. T_.Swap(r.T_);
  919. }
  920. Y_REINITIALIZES_OBJECT inline void Reset(TCowPtr p) {
  921. p.Swap(*this);
  922. }
  923. Y_REINITIALIZES_OBJECT inline void Reset() {
  924. T_.Reset();
  925. }
  926. #ifdef __cpp_impl_three_way_comparison
  927. template <class Other>
  928. inline bool operator==(const Other& p) const noexcept {
  929. return (p == Get());
  930. }
  931. #endif
  932. private:
  933. inline void Unshare() {
  934. if (Shared()) {
  935. Reset(TCopy::Copy(T_.Get()));
  936. }
  937. }
  938. private:
  939. TPtr T_;
  940. };
  941. // saves .Get() on argument passing. Intended usage: Func(TPtrArg<X> p); ... TIntrusivePtr<X> p2; Func(p2);
  942. template <class T>
  943. class TPtrArg {
  944. T* Ptr;
  945. public:
  946. TPtrArg(T* p)
  947. : Ptr(p)
  948. {
  949. }
  950. TPtrArg(const TIntrusivePtr<T>& p)
  951. : Ptr(p.Get())
  952. {
  953. }
  954. operator T*() const {
  955. return Ptr;
  956. }
  957. T* operator->() const {
  958. return Ptr;
  959. }
  960. T* Get() const {
  961. return Ptr;
  962. }
  963. };