#ifndef HEADER_BASE_CPOOLSHAREDPTR #define HEADER_BASE_CPOOLSHAREDPTR #include #include #include #include "MemoryPool.h" namespace base { class CRefCount; template class CMemWeakPtr; template class CMemSharePtr; enum MemoryType { TYPE_NEW = 0x00, TYPE_MALLOC = 0x01, }; template class CEnableSharedFromThis { public: typedef Ty _EStype; CMemSharePtr memshared_from_this() { return (_weak_ptr.Lock()); } protected: constexpr CEnableSharedFromThis() noexcept { } CEnableSharedFromThis(const CEnableSharedFromThis&) noexcept { } CEnableSharedFromThis& operator=(const CEnableSharedFromThis&) noexcept { return (*this); } ~CEnableSharedFromThis() noexcept { } private: template friend void DoEnable(T1 *ptr, CEnableSharedFromThis *es, CRefCount *ref_ptr, CMemoryPool* pool, int size, MemoryType type); CMemWeakPtr _weak_ptr; }; // reset internal weak pointer template inline void DoEnable(T1 *ptr, CEnableSharedFromThis *es, CRefCount *ref_ptr, CMemoryPool* pool = nullptr, int size = 0, MemoryType type = TYPE_NEW) { es->_weak_ptr.Resetw(ptr, ref_ptr, pool, size, type); } //not useful on gcc. //template //struct has_member_weak_ptr { // template // static auto check(_T)->typename std::decay::type; // static void check(...); // using type = decltype(check(std::declval())); // enum { value = !std::is_void::value }; //}; template inline void EnableShared(Ty *ptr, CRefCount *ref_ptr, CMemoryPool* pool = nullptr, int size = 0, MemoryType type = TYPE_NEW, typename Ty::_EStype * = 0) { if (ptr) { DoEnable(ptr, (CEnableSharedFromThis*)ptr, ref_ptr, pool, size, type); } } inline void EnableShared(const volatile void *, const volatile void *, CMemoryPool* = nullptr, int = 0, MemoryType = TYPE_NEW) { } //reference count class class CRefCount { public: // construct CRefCount() : _uses(1), _weaks(0) {} // ensure that derived classes can be destroyed properly virtual ~CRefCount() noexcept {} // increment use count void IncrefUse() { _uses++; } // increment weak reference count void IncrefWeak() { _weaks++; } //decrement use count bool DecrefUse() { if (--_uses == 0) { return true; } return false; } // decrement weak reference count bool DecrefWeak() { if (--_weaks == 0) { return true; } return false; } // return use count long GetUseCount() const { return _uses; } // return weak count long GetWeakCount() const { return _weaks; } // return true if _uses == 0 bool Expired() const { return (_uses == 0); } private: std::atomic_long _uses; std::atomic_long _weaks; }; // base class for CMemSharePtr and CMemWeakPtr template class CBasePtr { public: typedef CBasePtr _BasePtr; // construct CBasePtr() noexcept : _ptr(nullptr), _ref_count(nullptr), _pool(nullptr) { EnableShared(_ptr, _ref_count, _pool); } CBasePtr(T* ptr, CRefCount* ref, CMemoryPool* pool, MemoryType type, int large_size = 0) noexcept : _ptr(ptr), _ref_count(ref), _pool(pool), _malloc_size(large_size), _memory_type(type) { EnableShared(_ptr, _ref_count, _pool, _malloc_size, _memory_type); } // construct CBasePtr object that takes resource from _Right CBasePtr(const _BasePtr& r) : _ptr(r._ptr), _ref_count(r._ref_count), _pool(r._pool), _malloc_size(r._malloc_size), _memory_type(r._memory_type) { if (_ref_count) { _ref_count->IncrefUse(); } EnableShared(_ptr, _ref_count, _pool, _malloc_size, _memory_type); } // construct CBasePtr object that takes resource from _Right CBasePtr(_BasePtr&& r) : _ptr(r._ptr), _ref_count(r._ref_count), _pool(r._pool), _memory_type(r._memory_type), _malloc_size(r._malloc_size) { r._ptr = nullptr; r._ref_count = nullptr; r._pool = nullptr; _malloc_size = 0; EnableShared(_ptr, _ref_count, _pool, _malloc_size, _memory_type); } // construct CBasePtr object that takes resource from _Right _BasePtr& operator=(_BasePtr&& r) { if (_ref_count) { _ref_count->DecrefUse(); } _ptr = r._ptr; _ref_count = r._ref_count; _pool = r._pool; _memory_type = r._memory_type; _malloc_size = r._malloc_size; r._ptr = nullptr; r._ref_count = nullptr; r._pool = nullptr; r._malloc_size = 0; return (*this); } // construct CBasePtr object that takes resource from _Right _BasePtr& operator=(const _BasePtr& r) { if (_ref_count) { _ref_count->DecrefUse(); } _ptr = r._ptr; _ref_count = r._ref_count; _memory_type = r._memory_type; _malloc_size = r._malloc_size; _pool = r._pool; if (_ref_count) { _ref_count->IncrefUse(); } return (*this); } // return use count long UseCount() const noexcept { return (_ref_count ? _ref_count->GetUseCount() : 0); } // return pointer to resource T* Get() noexcept { std::unique_lock lock(_mutex); return (_ptr); } // test if expired bool Expired() noexcept { return (!_ref_count || _ref_count->Expired()); } // release resource void Reset() { Reset(0, 0); } // release resource and take ownership from CMemWeakPtr _Other._Ptr void Reset(const _BasePtr& other) { Reset(other._ptr, other._ref_count, other._pool); } // release resource and take _Other_ptr through _Other_rep void Reset(T *other_ptr, CRefCount * other_rep, CMemoryPool* pool) { _Reset0(other_ptr, other_rep, pool); } // release weak reference to resource void Resetw() { _Resetw(0, 0); } // release weak reference to resource and take _Other._Ptr void Resetw(_BasePtr& other) { Resetw(other._ptr, other._ref_count, other._pool); } void Resetw(T *other_ptr, CRefCount *other_rep, CMemoryPool* pool) { _Resetw0(other_ptr, other_rep, pool); } void Resetw(T *other_ptr, CRefCount *other_rep, CMemoryPool* pool, int size, MemoryType type) { _Resetw0(other_ptr, other_rep, pool, type, size); } public: // release resource and take _Other_ptr through _Other_rep void Reset(T *other_ptr, CRefCount * other_rep) { _Reset0(other_ptr, other_rep); } // release resource and take new resource void _Reset0(T *other_ptr, CRefCount *other_rep) { if (other_rep) { other_rep->IncrefUse(); } if (_ref_count && _ref_count->GetUseCount() > 0) { _DecrefUse(); } std::unique_lock lock(_mutex); _ref_count = other_rep; _ptr = other_ptr; _pool = nullptr; } // release resource and take new resource void _Reset0(T *other_ptr, CRefCount *other_rep, CMemoryPool* pool, int size = 0, MemoryType type = TYPE_NEW) { if (other_rep) { other_rep->IncrefUse(); } if (_ref_count && _ref_count->GetUseCount() > 0) { _DecrefUse(); } std::unique_lock lock(_mutex); _ref_count = other_rep; _ptr = other_ptr; _pool = pool; _malloc_size = size; _memory_type = type; } // decrement use reference count void _DecrefUse() { if (_ref_count && _ref_count->DecrefUse()) { _Destroy(); } } // decrement use reference count void _DecrefWeak() { if (_ref_count && _ref_count->DecrefWeak()) { _DestroyThis(); } } // point to _Other_ptr through _Other_rep void _Resetw(T *other_ptr, CRefCount *other_rep) { _Resetw0(other_ptr, other_rep); } // release resource and take new resource void _Resetw0(T *other_ptr, CRefCount *other_rep) { if (other_rep) { other_rep->IncrefWeak(); } if (_ref_count && _ref_count->GetWeakCount() > 0) { _DecrefWeak(); } std::unique_lock lock(_mutex); _ref_count = other_rep; _ptr = other_ptr; _pool = nullptr; } // release resource and take new resource void _Resetw0(T *other_ptr, CRefCount *other_rep, CMemoryPool* pool) { if (other_rep) { other_rep->IncrefWeak(); } if (_ref_count && _ref_count->GetWeakCount() > 0) { _DecrefWeak(); } std::unique_lock lock(_mutex); _ref_count = other_rep; _ptr = other_ptr; _pool = pool; } // release resource and take new resource void _Resetw0(T *other_ptr, CRefCount *other_rep, CMemoryPool* pool, MemoryType type, int size) { if (other_rep) { other_rep->IncrefWeak(); } if (_ref_count && _ref_count->GetWeakCount() > 0) { _DecrefWeak(); } std::unique_lock lock(_mutex); _ref_count = other_rep; _ptr = other_ptr; _pool = pool; _memory_type = type; _malloc_size = size; } //release resource void _Destroy() noexcept { if (_pool) { switch (_memory_type) { case TYPE_MALLOC: _pool->PoolFree(_ptr, _malloc_size); break; case TYPE_NEW: _pool->PoolDelete(_ptr); break; } _pool->PoolDelete(_ref_count); } } void _DestroyThis() noexcept { } virtual ~CBasePtr() {} protected: T *_ptr; //real data ptr CRefCount *_ref_count; CMemoryPool *_pool; //base memory pool int _malloc_size; //if malloc large memory from pool. that use to free MemoryType _memory_type; //malloc memory type from pool std::mutex _mutex; }; // class for reference counted resource management template class CMemSharePtr : public CBasePtr { public: typedef CBasePtr _BasePtr; // construct CMemSharePtr() noexcept : _BasePtr() {} CMemSharePtr(nullptr_t) noexcept : _BasePtr() {} CMemSharePtr(T* ptr, CRefCount* ref, CMemoryPool* pool, MemoryType type, int large_size = 0) noexcept : _BasePtr(ptr, ref, pool, type, large_size) {} CMemSharePtr(const _BasePtr& r) : _BasePtr(r) {} CMemSharePtr(_BasePtr&& r) : _BasePtr(r) {} CMemSharePtr& operator=(_BasePtr&& r) { _BasePtr::operator=(r); return (*this); } CMemSharePtr& operator=(const _BasePtr& r) { _BasePtr::operator=(r); return (*this); } ~CMemSharePtr() { this->_DecrefUse(); } _BasePtr& operator==(const _BasePtr& r) noexcept { return this->_ptr == r._ptr; } // return pointer to resource T *operator->() noexcept { return (this->Get()); } // return pointer to resource T& operator*() noexcept { return (*(this->Get())); } // return true if no other CMemSharePtr object owns this resource bool unique() const noexcept { std::unique_lock lock(this->_mutex); return (this->UseCount() == 1); } // test if CMemSharePtr object owns no resource explicit operator bool() noexcept { return (this->Get() != 0); } }; // class for pointer to reference counted resource. // construc from CMemSharePtr template class CMemWeakPtr : public CBasePtr { public: typedef CBasePtr _BasePtr; CMemWeakPtr() { this->Resetw(); } CMemWeakPtr(_BasePtr& r) { this->Resetw(r); } // construct CBasePtr object that takes resource from _Right CMemWeakPtr& operator=(_BasePtr&& r) { _BasePtr::operator=(r); return (*this); } // construct CBasePtr object that takes resource from _Right CMemWeakPtr& operator=(CMemSharePtr&& r) { this->Resetw(r); return (*this); } // construct CBasePtr object that takes resource from _Right CMemWeakPtr& operator=(CMemWeakPtr&& r) { this->Resetw(r); return (*this); } // construct CBasePtr object that takes resource from _Right CMemWeakPtr& operator=(CMemSharePtr& r) { this->Resetw(r); return (*this); } // construct CBasePtr object that takes resource from _Right CMemWeakPtr& operator=(CMemWeakPtr& r) { this->Resetw(r); return (*this); } // release resource ~CMemWeakPtr() noexcept { this->_DecrefWeak(); } // convert to CMemSharePtr CMemSharePtr Lock() noexcept { //std::unique_lock lock(this->_mutex); if (this->Expired()) { return CMemWeakPtr(); } return (CMemSharePtr(*this)); } // test if CMemSharePtr object owns no resource explicit operator bool() noexcept { return (this->Get() != 0); } }; //new object on pool template CMemSharePtr MakeNewSharedPtr(CMemoryPool* pool, Args&&... args) { T* o = pool->PoolNew(std::forward(args)...); CRefCount* ref = pool->PoolNew(); return CMemSharePtr(o, ref, pool, TYPE_NEW); } //malloc from pool template CMemSharePtr MakeMallocSharedPtr(CMemoryPool* pool, int size) { T* o = (T*)pool->PoolMalloc(size); CRefCount* ref = pool->PoolNew(); return CMemSharePtr(o, ref, pool, TYPE_MALLOC, size); } } #endif