ysafeptr.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438
  1. #pragma once
  2. #include <stddef.h>
  3. #include <util/system/compiler.h>
  4. #include <util/system/yassert.h>
  5. #include <util/system/defaults.h>
  6. #include <util/system/tls.h>
  7. ////////////////////////////////////////////////////////////////////////////////////////////////////
  8. // There are different templates of pointers:
  9. // 1. Simple pointers.
  10. // 2. TPtr with refereces.
  11. // 3. TObj/TMObj with ownership. After destruction of a TObj the object it referenced to is
  12. // cleaned up and marked as non valid. Similarly does TMobj organizing the parallel ownership
  13. // of an object.
  14. //
  15. // Limitations:
  16. // 1. It may be necessary to use BASIC_REGISTER_CLASS() in .cpp files to be able to use a
  17. // pointer to a forward declared class.
  18. // 2. It's prohibited to override the 'new' operator, since the standard 'delete' will be used
  19. // for destruction of objects (because of 'delete this').
  20. ////////////////////////////////////////////////////////////////////////////////////////////////////
  21. #if defined(_MSC_VER) && defined(_DEBUG)
  22. #include <util/system/winint.h>
  23. #define CHECK_YPTR2
  24. #endif
  25. struct IBinSaver;
  26. class IObjectBase {
  27. private:
  28. #ifdef CHECK_YPTR2
  29. static Y_POD_THREAD(bool) DisableThreadCheck;
  30. void CheckThreadId() {
  31. if (dwThreadId == 0) {
  32. dwThreadId = GetCurrentThreadId();
  33. } else {
  34. Y_ASSERT(dwThreadId == GetCurrentThreadId() || DisableThreadCheck);
  35. }
  36. }
  37. void AddRef() {
  38. CheckThreadId();
  39. ++RefData;
  40. }
  41. void AddObj(int nRef) {
  42. CheckThreadId();
  43. ObjData += nRef;
  44. }
  45. #else
  46. void CheckThreadId() {
  47. }
  48. void AddRef() {
  49. ++RefData;
  50. }
  51. void AddObj(int nRef) {
  52. ObjData += nRef;
  53. }
  54. #endif
  55. void ReleaseRefComplete();
  56. void ReleaseObjComplete(int nMask);
  57. void DecRef() {
  58. CheckThreadId();
  59. --RefData;
  60. }
  61. void DecObj(int nRef) {
  62. CheckThreadId();
  63. ObjData -= nRef;
  64. }
  65. void ReleaseRef() {
  66. CheckThreadId();
  67. --RefData;
  68. if (RefData == 0) {
  69. ReleaseRefComplete();
  70. }
  71. }
  72. void ReleaseObj(int nRef, int nMask) {
  73. CheckThreadId();
  74. ObjData -= nRef;
  75. if ((ObjData & nMask) == 0) {
  76. ReleaseObjComplete(nMask);
  77. }
  78. }
  79. protected:
  80. #ifdef CHECK_YPTR2
  81. DWORD dwThreadId;
  82. #endif
  83. ui32 ObjData;
  84. ui32 RefData;
  85. // function should clear contents of object, easy to implement via consequent calls to
  86. // destructor and constructor, this function should not be called directly, use Clear()
  87. virtual void DestroyContents() = 0;
  88. virtual ~IObjectBase() = default;
  89. inline void CopyValidFlag(const IObjectBase& a) {
  90. ObjData &= 0x7fffffff;
  91. ObjData |= a.ObjData & 0x80000000;
  92. }
  93. public:
  94. IObjectBase()
  95. : ObjData(0)
  96. , RefData(0)
  97. {
  98. #ifdef CHECK_YPTR2
  99. dwThreadId = 0;
  100. #endif
  101. }
  102. // do not copy refcount when copy object
  103. IObjectBase(const IObjectBase& a)
  104. : ObjData(0)
  105. , RefData(0)
  106. {
  107. #ifdef CHECK_YPTR2
  108. dwThreadId = 0;
  109. #endif
  110. CopyValidFlag(a);
  111. }
  112. IObjectBase& operator=(const IObjectBase& a) {
  113. CopyValidFlag(a);
  114. return *this;
  115. }
  116. #ifdef CHECK_YPTR2
  117. static void SetThreadCheckMode(bool val) {
  118. DisableThreadCheck = !val;
  119. }
  120. void ResetThreadId() {
  121. Y_ASSERT(RefData == 0 && ObjData == 0); // can reset thread check only for ref free objects
  122. dwThreadId = 0;
  123. }
  124. #else
  125. static void SetThreadCheckMode(bool) {
  126. }
  127. void ResetThreadId() {
  128. }
  129. #endif
  130. // class name of derived class
  131. virtual const char* GetClassName() const = 0;
  132. ui32 IsRefInvalid() const {
  133. return (ObjData & 0x80000000);
  134. }
  135. ui32 IsRefValid() const {
  136. return !IsRefInvalid();
  137. }
  138. // reset data in class to default values, saves RefCount from destruction
  139. void Clear() {
  140. AddRef();
  141. DestroyContents();
  142. DecRef();
  143. }
  144. virtual int operator&(IBinSaver&) {
  145. return 0;
  146. }
  147. struct TRefO {
  148. void AddRef(IObjectBase* pObj) {
  149. pObj->AddObj(1);
  150. }
  151. void DecRef(IObjectBase* pObj) {
  152. pObj->DecObj(1);
  153. }
  154. void Release(IObjectBase* pObj) {
  155. pObj->ReleaseObj(1, 0x000fffff);
  156. }
  157. };
  158. struct TRefM {
  159. void AddRef(IObjectBase* pObj) {
  160. pObj->AddObj(0x100000);
  161. }
  162. void DecRef(IObjectBase* pObj) {
  163. pObj->DecObj(0x100000);
  164. }
  165. void Release(IObjectBase* pObj) {
  166. pObj->ReleaseObj(0x100000, 0x3ff00000);
  167. }
  168. };
  169. struct TRef {
  170. void AddRef(IObjectBase* pObj) {
  171. pObj->AddRef();
  172. }
  173. void DecRef(IObjectBase* pObj) {
  174. pObj->DecRef();
  175. }
  176. void Release(IObjectBase* pObj) {
  177. pObj->ReleaseRef();
  178. }
  179. };
  180. friend struct IObjectBase::TRef;
  181. friend struct IObjectBase::TRefO;
  182. friend struct IObjectBase::TRefM;
  183. };
  184. ////////////////////////////////////////////////////////////////////////////////////////////////////
  185. // macro that helps to create neccessary members for proper operation of refcount system
  186. // if class needs special destructor, use CFundament
  187. #define OBJECT_METHODS(classname) \
  188. public: \
  189. virtual const char* GetClassName() const override { \
  190. return #classname; \
  191. } \
  192. static IObjectBase* NewSaveLoadNullItem() { \
  193. return new classname(); \
  194. } \
  195. \
  196. protected: \
  197. virtual void DestroyContents() override { \
  198. this->~classname(); \
  199. int nHoldRefs = this->RefData, nHoldObjs = this->ObjData; \
  200. new (this) classname(); \
  201. this->RefData += nHoldRefs; \
  202. this->ObjData += nHoldObjs; \
  203. } \
  204. \
  205. private: \
  206. Y_SEMICOLON_GUARD
  207. #define OBJECT_NOCOPY_METHODS(classname) OBJECT_METHODS(classname)
  208. #define BASIC_REGISTER_CLASS(classname) \
  209. Y_PRAGMA_DIAGNOSTIC_PUSH \
  210. Y_PRAGMA_NO_UNUSED_FUNCTION \
  211. template <> \
  212. IObjectBase* CastToObjectBaseImpl<classname>(classname * p, void*) { \
  213. return p; \
  214. } \
  215. template <> \
  216. classname* CastToUserObjectImpl<classname>(IObjectBase * p, classname*, void*) { \
  217. return dynamic_cast<classname*>(p); \
  218. } \
  219. Y_PRAGMA_DIAGNOSTIC_POP
  220. ////////////////////////////////////////////////////////////////////////////////////////////////////
  221. template <class TUserObj>
  222. IObjectBase* CastToObjectBaseImpl(TUserObj* p, void*);
  223. template <class TUserObj>
  224. IObjectBase* CastToObjectBaseImpl(TUserObj* p, IObjectBase*) {
  225. return p;
  226. }
  227. template <class TUserObj>
  228. TUserObj* CastToUserObjectImpl(IObjectBase* p, TUserObj*, void*);
  229. template <class TUserObj>
  230. TUserObj* CastToUserObjectImpl(IObjectBase* _p, TUserObj*, IObjectBase*) {
  231. return dynamic_cast<TUserObj*>(_p);
  232. }
  233. template <class TUserObj>
  234. inline IObjectBase* CastToObjectBase(TUserObj* p) {
  235. return CastToObjectBaseImpl(p, p);
  236. }
  237. template <class TUserObj>
  238. inline const IObjectBase* CastToObjectBase(const TUserObj* p) {
  239. return p;
  240. }
  241. template <class TUserObj>
  242. inline TUserObj* CastToUserObject(IObjectBase* p, TUserObj* pu) {
  243. return CastToUserObjectImpl(p, pu, pu);
  244. }
  245. ////////////////////////////////////////////////////////////////////////////////////////////////////
  246. // TObject - base object for reference counting, TUserObj - user object name
  247. // TRef - struct with AddRef/DecRef/Release methods for refcounting to use
  248. template <class TUserObj, class TRef>
  249. class TPtrBase {
  250. private:
  251. TUserObj* ptr;
  252. void AddRef(TUserObj* _ptr) {
  253. TRef p;
  254. if (_ptr) {
  255. p.AddRef(CastToObjectBase(_ptr));
  256. }
  257. }
  258. void DecRef(TUserObj* _ptr) {
  259. TRef p;
  260. if (_ptr) {
  261. p.DecRef(CastToObjectBase(_ptr));
  262. }
  263. }
  264. void Release(TUserObj* _ptr) {
  265. TRef p;
  266. if (_ptr) {
  267. p.Release(CastToObjectBase(_ptr));
  268. }
  269. }
  270. protected:
  271. void SetObject(TUserObj* _ptr) {
  272. TUserObj* pOld = ptr;
  273. ptr = _ptr;
  274. AddRef(ptr);
  275. Release(pOld);
  276. }
  277. public:
  278. TPtrBase()
  279. : ptr(nullptr)
  280. {
  281. }
  282. TPtrBase(TUserObj* _ptr)
  283. : ptr(_ptr)
  284. {
  285. AddRef(ptr);
  286. }
  287. TPtrBase(const TPtrBase& a)
  288. : ptr(a.ptr)
  289. {
  290. AddRef(ptr);
  291. }
  292. ~TPtrBase() {
  293. Release(ptr);
  294. }
  295. void Set(TUserObj* _ptr) {
  296. SetObject(_ptr);
  297. }
  298. TUserObj* Extract() {
  299. TUserObj* pRes = ptr;
  300. DecRef(ptr);
  301. ptr = nullptr;
  302. return pRes;
  303. }
  304. const char* GetClassName() const {
  305. return ptr->GetClassName();
  306. }
  307. // assignment operators
  308. TPtrBase& operator=(TUserObj* _ptr) {
  309. Set(_ptr);
  310. return *this;
  311. }
  312. TPtrBase& operator=(const TPtrBase& a) {
  313. Set(a.ptr);
  314. return *this;
  315. }
  316. // access
  317. TUserObj* operator->() const {
  318. return ptr;
  319. }
  320. operator TUserObj*() const {
  321. return ptr;
  322. }
  323. TUserObj* Get() const {
  324. return ptr;
  325. }
  326. IObjectBase* GetBarePtr() const {
  327. return CastToObjectBase(ptr);
  328. }
  329. int operator&(IBinSaver& f);
  330. };
  331. ////////////////////////////////////////////////////////////////////////////////////////////////////
  332. template <class T>
  333. inline bool IsValid(T* p) {
  334. return p != nullptr && !CastToObjectBase(p)->IsRefInvalid();
  335. }
  336. template <class T, class TRef>
  337. inline bool IsValid(const TPtrBase<T, TRef>& p) {
  338. return p.Get() && !p.GetBarePtr()->IsRefInvalid();
  339. }
  340. ////////////////////////////////////////////////////////////////////////////////////////////////////
  341. #define BASIC_PTR_DECLARE(TPtrName, TRef) \
  342. template <class T> \
  343. class TPtrName: public TPtrBase<T, TRef> { \
  344. using CBase = TPtrBase<T, TRef>; \
  345. \
  346. public: \
  347. using CDestType = T; \
  348. TPtrName() { \
  349. } \
  350. TPtrName(T* _ptr) \
  351. : CBase(_ptr) \
  352. { \
  353. } \
  354. TPtrName(const TPtrName& a) \
  355. : CBase(a) \
  356. { \
  357. } \
  358. TPtrName& operator=(T* _ptr) { \
  359. this->Set(_ptr); \
  360. return *this; \
  361. } \
  362. TPtrName& operator=(const TPtrName& a) { \
  363. this->SetObject(a.Get()); \
  364. return *this; \
  365. } \
  366. int operator&(IBinSaver& f) { \
  367. return (*(CBase*)this) & (f); \
  368. } \
  369. };
  370. BASIC_PTR_DECLARE(TPtr, IObjectBase::TRef)
  371. BASIC_PTR_DECLARE(TObj, IObjectBase::TRefO)
  372. BASIC_PTR_DECLARE(TMObj, IObjectBase::TRefM)
  373. // misuse guard
  374. template <class T>
  375. inline bool IsValid(TObj<T>* p) {
  376. return p->YouHaveMadeMistake();
  377. }
  378. template <class T>
  379. inline bool IsValid(TPtr<T>* p) {
  380. return p->YouHaveMadeMistake();
  381. }
  382. template <class T>
  383. inline bool IsValid(TMObj<T>* p) {
  384. return p->YouHaveMadeMistake();
  385. }
  386. ////////////////////////////////////////////////////////////////////////////////////////////////////
  387. // assumes base class is IObjectBase
  388. template <class T>
  389. class TDynamicCast {
  390. T* ptr;
  391. public:
  392. template <class TT>
  393. TDynamicCast(TT* _ptr) {
  394. ptr = dynamic_cast<T*>(CastToObjectBase(_ptr));
  395. }
  396. template <class TT>
  397. TDynamicCast(const TT* _ptr) {
  398. ptr = dynamic_cast<T*>(CastToObjectBase(const_cast<TT*>(_ptr)));
  399. }
  400. template <class T1, class T2>
  401. TDynamicCast(const TPtrBase<T1, T2>& _ptr) {
  402. ptr = dynamic_cast<T*>(_ptr.GetBarePtr());
  403. }
  404. operator T*() const {
  405. return ptr;
  406. }
  407. T* operator->() const {
  408. return ptr;
  409. }
  410. T* Get() const {
  411. return ptr;
  412. }
  413. };
  414. template <class T>
  415. inline bool IsValid(const TDynamicCast<T>& p) {
  416. return IsValid(p.Get());
  417. }