123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432 |
- #pragma once
- #include <stddef.h>
- #include <util/system/compiler.h>
- #include <util/system/yassert.h>
- #include <util/system/defaults.h>
- #include <util/system/tls.h>
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- // There are different templates of pointers:
- // 1. Simple pointers.
- // 2. TPtr with refereces.
- // 3. TObj/TMObj with ownership. After destruction of a TObj the object it referenced to is
- // cleaned up and marked as non valid. Similarly does TMobj organizing the parallel ownership
- // of an object.
- //
- // Limitations:
- // 1. It may be necessary to use BASIC_REGISTER_CLASS() in .cpp files to be able to use a
- // pointer to a forward declared class.
- // 2. It's prohibited to override the 'new' operator, since the standard 'delete' will be used
- // for destruction of objects (because of 'delete this').
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- #if defined(_MSC_VER) && defined(_DEBUG)
- #include <util/system/winint.h>
- #define CHECK_YPTR2
- #endif
- struct IBinSaver;
- class IObjectBase {
- private:
- #ifdef CHECK_YPTR2
- static Y_POD_THREAD(bool) DisableThreadCheck;
- void CheckThreadId() {
- if (dwThreadId == 0)
- dwThreadId = GetCurrentThreadId();
- else
- Y_ASSERT(dwThreadId == GetCurrentThreadId() || DisableThreadCheck);
- }
- void AddRef() {
- CheckThreadId();
- ++RefData;
- }
- void AddObj(int nRef) {
- CheckThreadId();
- ObjData += nRef;
- }
- #else
- void CheckThreadId() {
- }
- void AddRef() {
- ++RefData;
- }
- void AddObj(int nRef) {
- ObjData += nRef;
- }
- #endif
- void ReleaseRefComplete();
- void ReleaseObjComplete(int nMask);
- void DecRef() {
- CheckThreadId();
- --RefData;
- }
- void DecObj(int nRef) {
- CheckThreadId();
- ObjData -= nRef;
- }
- void ReleaseRef() {
- CheckThreadId();
- --RefData;
- if (RefData == 0)
- ReleaseRefComplete();
- }
- void ReleaseObj(int nRef, int nMask) {
- CheckThreadId();
- ObjData -= nRef;
- if ((ObjData & nMask) == 0)
- ReleaseObjComplete(nMask);
- }
- protected:
- #ifdef CHECK_YPTR2
- DWORD dwThreadId;
- #endif
- ui32 ObjData;
- ui32 RefData;
- // function should clear contents of object, easy to implement via consequent calls to
- // destructor and constructor, this function should not be called directly, use Clear()
- virtual void DestroyContents() = 0;
- virtual ~IObjectBase() = default;
- inline void CopyValidFlag(const IObjectBase& a) {
- ObjData &= 0x7fffffff;
- ObjData |= a.ObjData & 0x80000000;
- }
- public:
- IObjectBase()
- : ObjData(0)
- , RefData(0)
- {
- #ifdef CHECK_YPTR2
- dwThreadId = 0;
- #endif
- }
- // do not copy refcount when copy object
- IObjectBase(const IObjectBase& a)
- : ObjData(0)
- , RefData(0)
- {
- #ifdef CHECK_YPTR2
- dwThreadId = 0;
- #endif
- CopyValidFlag(a);
- }
- IObjectBase& operator=(const IObjectBase& a) {
- CopyValidFlag(a);
- return *this;
- }
- #ifdef CHECK_YPTR2
- static void SetThreadCheckMode(bool val) {
- DisableThreadCheck = !val;
- }
- void ResetThreadId() {
- Y_ASSERT(RefData == 0 && ObjData == 0); // can reset thread check only for ref free objects
- dwThreadId = 0;
- }
- #else
- static void SetThreadCheckMode(bool) {
- }
- void ResetThreadId() {
- }
- #endif
- // class name of derived class
- virtual const char* GetClassName() const = 0;
- ui32 IsRefInvalid() const {
- return (ObjData & 0x80000000);
- }
- ui32 IsRefValid() const {
- return !IsRefInvalid();
- }
- // reset data in class to default values, saves RefCount from destruction
- void Clear() {
- AddRef();
- DestroyContents();
- DecRef();
- }
- virtual int operator&(IBinSaver&) {
- return 0;
- }
- struct TRefO {
- void AddRef(IObjectBase* pObj) {
- pObj->AddObj(1);
- }
- void DecRef(IObjectBase* pObj) {
- pObj->DecObj(1);
- }
- void Release(IObjectBase* pObj) {
- pObj->ReleaseObj(1, 0x000fffff);
- }
- };
- struct TRefM {
- void AddRef(IObjectBase* pObj) {
- pObj->AddObj(0x100000);
- }
- void DecRef(IObjectBase* pObj) {
- pObj->DecObj(0x100000);
- }
- void Release(IObjectBase* pObj) {
- pObj->ReleaseObj(0x100000, 0x3ff00000);
- }
- };
- struct TRef {
- void AddRef(IObjectBase* pObj) {
- pObj->AddRef();
- }
- void DecRef(IObjectBase* pObj) {
- pObj->DecRef();
- }
- void Release(IObjectBase* pObj) {
- pObj->ReleaseRef();
- }
- };
- friend struct IObjectBase::TRef;
- friend struct IObjectBase::TRefO;
- friend struct IObjectBase::TRefM;
- };
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- // macro that helps to create neccessary members for proper operation of refcount system
- // if class needs special destructor, use CFundament
- #define OBJECT_METHODS(classname) \
- public: \
- virtual const char* GetClassName() const override { \
- return #classname; \
- } \
- static IObjectBase* NewSaveLoadNullItem() { \
- return new classname(); \
- } \
- \
- protected: \
- virtual void DestroyContents() override { \
- this->~classname(); \
- int nHoldRefs = this->RefData, nHoldObjs = this->ObjData; \
- new (this) classname(); \
- this->RefData += nHoldRefs; \
- this->ObjData += nHoldObjs; \
- } \
- \
- private: \
- Y_SEMICOLON_GUARD
- #define OBJECT_NOCOPY_METHODS(classname) OBJECT_METHODS(classname)
- #define BASIC_REGISTER_CLASS(classname) \
- Y_PRAGMA_DIAGNOSTIC_PUSH \
- Y_PRAGMA_NO_UNUSED_FUNCTION \
- template <> \
- IObjectBase* CastToObjectBaseImpl<classname>(classname * p, void*) { \
- return p; \
- } \
- template <> \
- classname* CastToUserObjectImpl<classname>(IObjectBase * p, classname*, void*) { \
- return dynamic_cast<classname*>(p); \
- } \
- Y_PRAGMA_DIAGNOSTIC_POP
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- template <class TUserObj>
- IObjectBase* CastToObjectBaseImpl(TUserObj* p, void*);
- template <class TUserObj>
- IObjectBase* CastToObjectBaseImpl(TUserObj* p, IObjectBase*) {
- return p;
- }
- template <class TUserObj>
- TUserObj* CastToUserObjectImpl(IObjectBase* p, TUserObj*, void*);
- template <class TUserObj>
- TUserObj* CastToUserObjectImpl(IObjectBase* _p, TUserObj*, IObjectBase*) {
- return dynamic_cast<TUserObj*>(_p);
- }
- template <class TUserObj>
- inline IObjectBase* CastToObjectBase(TUserObj* p) {
- return CastToObjectBaseImpl(p, p);
- }
- template <class TUserObj>
- inline const IObjectBase* CastToObjectBase(const TUserObj* p) {
- return p;
- }
- template <class TUserObj>
- inline TUserObj* CastToUserObject(IObjectBase* p, TUserObj* pu) {
- return CastToUserObjectImpl(p, pu, pu);
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- // TObject - base object for reference counting, TUserObj - user object name
- // TRef - struct with AddRef/DecRef/Release methods for refcounting to use
- template <class TUserObj, class TRef>
- class TPtrBase {
- private:
- TUserObj* ptr;
- void AddRef(TUserObj* _ptr) {
- TRef p;
- if (_ptr)
- p.AddRef(CastToObjectBase(_ptr));
- }
- void DecRef(TUserObj* _ptr) {
- TRef p;
- if (_ptr)
- p.DecRef(CastToObjectBase(_ptr));
- }
- void Release(TUserObj* _ptr) {
- TRef p;
- if (_ptr)
- p.Release(CastToObjectBase(_ptr));
- }
- protected:
- void SetObject(TUserObj* _ptr) {
- TUserObj* pOld = ptr;
- ptr = _ptr;
- AddRef(ptr);
- Release(pOld);
- }
- public:
- TPtrBase()
- : ptr(nullptr)
- {
- }
- TPtrBase(TUserObj* _ptr)
- : ptr(_ptr)
- {
- AddRef(ptr);
- }
- TPtrBase(const TPtrBase& a)
- : ptr(a.ptr)
- {
- AddRef(ptr);
- }
- ~TPtrBase() {
- Release(ptr);
- }
- void Set(TUserObj* _ptr) {
- SetObject(_ptr);
- }
- TUserObj* Extract() {
- TUserObj* pRes = ptr;
- DecRef(ptr);
- ptr = nullptr;
- return pRes;
- }
- const char* GetClassName() const {
- return ptr->GetClassName();
- }
- // assignment operators
- TPtrBase& operator=(TUserObj* _ptr) {
- Set(_ptr);
- return *this;
- }
- TPtrBase& operator=(const TPtrBase& a) {
- Set(a.ptr);
- return *this;
- }
- // access
- TUserObj* operator->() const {
- return ptr;
- }
- operator TUserObj*() const {
- return ptr;
- }
- TUserObj* Get() const {
- return ptr;
- }
- IObjectBase* GetBarePtr() const {
- return CastToObjectBase(ptr);
- }
- int operator&(IBinSaver& f);
- };
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- template <class T>
- inline bool IsValid(T* p) {
- return p != nullptr && !CastToObjectBase(p)->IsRefInvalid();
- }
- template <class T, class TRef>
- inline bool IsValid(const TPtrBase<T, TRef>& p) {
- return p.Get() && !p.GetBarePtr()->IsRefInvalid();
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- #define BASIC_PTR_DECLARE(TPtrName, TRef) \
- template <class T> \
- class TPtrName: public TPtrBase<T, TRef> { \
- using CBase = TPtrBase<T, TRef>; \
- \
- public: \
- using CDestType = T; \
- TPtrName() { \
- } \
- TPtrName(T* _ptr) \
- : CBase(_ptr) \
- { \
- } \
- TPtrName(const TPtrName& a) \
- : CBase(a) \
- { \
- } \
- TPtrName& operator=(T* _ptr) { \
- this->Set(_ptr); \
- return *this; \
- } \
- TPtrName& operator=(const TPtrName& a) { \
- this->SetObject(a.Get()); \
- return *this; \
- } \
- int operator&(IBinSaver& f) { \
- return (*(CBase*)this) & (f); \
- } \
- };
- BASIC_PTR_DECLARE(TPtr, IObjectBase::TRef)
- BASIC_PTR_DECLARE(TObj, IObjectBase::TRefO)
- BASIC_PTR_DECLARE(TMObj, IObjectBase::TRefM)
- // misuse guard
- template <class T>
- inline bool IsValid(TObj<T>* p) {
- return p->YouHaveMadeMistake();
- }
- template <class T>
- inline bool IsValid(TPtr<T>* p) {
- return p->YouHaveMadeMistake();
- }
- template <class T>
- inline bool IsValid(TMObj<T>* p) {
- return p->YouHaveMadeMistake();
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- // assumes base class is IObjectBase
- template <class T>
- class TDynamicCast {
- T* ptr;
- public:
- template <class TT>
- TDynamicCast(TT* _ptr) {
- ptr = dynamic_cast<T*>(CastToObjectBase(_ptr));
- }
- template <class TT>
- TDynamicCast(const TT* _ptr) {
- ptr = dynamic_cast<T*>(CastToObjectBase(const_cast<TT*>(_ptr)));
- }
- template <class T1, class T2>
- TDynamicCast(const TPtrBase<T1, T2>& _ptr) {
- ptr = dynamic_cast<T*>(_ptr.GetBarePtr());
- }
- operator T*() const {
- return ptr;
- }
- T* operator->() const {
- return ptr;
- }
- T* Get() const {
- return ptr;
- }
- };
- template <class T>
- inline bool IsValid(const TDynamicCast<T>& p) {
- return IsValid(p.Get());
- }
|