Files
CppNet/base/PoolSharedPtr.h
2020-01-07 23:03:38 +08:00

520 lines
16 KiB
C++

#ifndef HEADER_BASE_CPOOLSHAREDPTR
#define HEADER_BASE_CPOOLSHAREDPTR
#include <atomic>
#include <stddef.h>
#include <functional>
#include "MemoryPool.h"
namespace base {
class CRefCount;
template<class T>
class CMemWeakPtr;
template<class T>
class CMemSharePtr;
enum MemoryType {
TYPE_NEW = 0x00,
TYPE_MALLOC = 0x01,
};
template<class Ty>
class CEnableSharedFromThis {
public:
typedef Ty _EStype;
CMemSharePtr<Ty> 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<class T1, class T2>
friend void DoEnable(T1 *ptr, CEnableSharedFromThis<T2> *es, CRefCount *ref_ptr, CMemoryPool* pool, int size, MemoryType type);
CMemWeakPtr<Ty> _weak_ptr;
};
// reset internal weak pointer
template<class T1, class T2>
inline void DoEnable(T1 *ptr, CEnableSharedFromThis<T2> *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<typename T>
//struct has_member_weak_ptr {
// template <typename _T>
// static auto check(_T)->typename std::decay<decltype(_T::_weak_ptr)>::type;
// static void check(...);
// using type = decltype(check(std::declval<T>()));
// enum { value = !std::is_void<type>::value };
//};
template<class Ty>
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<typename Ty::_EStype>*)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<typename T>
class CBasePtr {
public:
typedef CBasePtr<T> _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<std::mutex> 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<std::mutex> 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<std::mutex> 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<std::mutex> 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<std::mutex> 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<std::mutex> 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<T>(_ptr, _malloc_size);
break;
case TYPE_NEW:
_pool->PoolDelete<T>(_ptr);
break;
}
_pool->PoolDelete<CRefCount>(_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 T>
class CMemSharePtr : public CBasePtr<T> {
public:
typedef CBasePtr<T> _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<std::mutex> 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 T>
class CMemWeakPtr : public CBasePtr<T> {
public:
typedef CBasePtr<T> _BasePtr;
CMemWeakPtr() {
this->Resetw();
}
CMemWeakPtr(_BasePtr& r) {
this->Resetw(r);
}
// construct CBasePtr object that takes resource from _Right
CMemWeakPtr<T>& operator=(_BasePtr&& r) {
_BasePtr::operator=(r);
return (*this);
}
// construct CBasePtr object that takes resource from _Right
CMemWeakPtr<T>& operator=(CMemSharePtr<T>&& r) {
this->Resetw(r);
return (*this);
}
// construct CBasePtr object that takes resource from _Right
CMemWeakPtr<T>& operator=(CMemWeakPtr<T>&& r) {
this->Resetw(r);
return (*this);
}
// construct CBasePtr object that takes resource from _Right
CMemWeakPtr<T>& operator=(CMemSharePtr<T>& r) {
this->Resetw(r);
return (*this);
}
// construct CBasePtr object that takes resource from _Right
CMemWeakPtr<T>& operator=(CMemWeakPtr<T>& r) {
this->Resetw(r);
return (*this);
}
// release resource
~CMemWeakPtr() noexcept {
this->_DecrefWeak();
}
// convert to CMemSharePtr
CMemSharePtr<T> Lock() noexcept {
//std::unique_lock<std::mutex> lock(this->_mutex);
if (this->Expired()) {
return CMemWeakPtr();
}
return (CMemSharePtr<T>(*this));
}
// test if CMemSharePtr object owns no resource
explicit operator bool() noexcept {
return (this->Get() != 0);
}
};
//new object on pool
template<typename T, typename... Args >
CMemSharePtr<T> MakeNewSharedPtr(CMemoryPool* pool, Args&&... args) {
T* o = pool->PoolNew<T>(std::forward<Args>(args)...);
CRefCount* ref = pool->PoolNew<CRefCount>();
return CMemSharePtr<T>(o, ref, pool, TYPE_NEW);
}
//malloc from pool
template<typename T>
CMemSharePtr<T> MakeMallocSharedPtr(CMemoryPool* pool, int size) {
T* o = (T*)pool->PoolMalloc<T>(size);
CRefCount* ref = pool->PoolNew<CRefCount>();
return CMemSharePtr<T>(o, ref, pool, TYPE_MALLOC, size);
}
}
#endif