ysafeptr.h 13 KB

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