ysafeptr.h 13 KB

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