mirror of
https://foundry.openuru.org/gitblit/r/CWE-ou-minkata.git
synced 2025-07-18 11:19:10 +00:00
@ -46,66 +46,124 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
#include "hsExceptions.h"
|
||||
#include "hsRefCnt.h"
|
||||
|
||||
#define REFCOUNT_DBG_NONE 0
|
||||
#define REFCOUNT_DBG_REFS 1
|
||||
#define REFCOUNT_DBG_LEAKS 2
|
||||
#define REFCOUNT_DBG_ALL 3
|
||||
#define REFCOUNT_DEBUGGING REFCOUNT_DBG_NONE
|
||||
|
||||
#if (REFCOUNT_DEBUGGING == REFCOUNT_DBG_LEAKS) || (REFCOUNT_DEBUGGING == REFCOUNT_DBG_ALL)
|
||||
#include <unordered_set>
|
||||
#include <mutex>
|
||||
#include "plFormat.h"
|
||||
|
||||
// hsDebugMessage can get overridden to dump to a file :(
|
||||
#ifdef _MSC_VER
|
||||
# include "hsWindows.h"
|
||||
# define _LeakDebug(message) OutputDebugString(message)
|
||||
#else
|
||||
# define _LeakDebug(message) fputs(message, stderr)
|
||||
#endif
|
||||
|
||||
struct _RefCountLeakCheck
|
||||
{
|
||||
std::unordered_set<hsRefCnt *> m_refs;
|
||||
unsigned m_added, m_removed;
|
||||
std::mutex m_mutex;
|
||||
|
||||
~_RefCountLeakCheck()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
|
||||
_LeakDebug(plFormat("Refs tracked: {} created, {} destroyed\n",
|
||||
m_added, m_removed).c_str());
|
||||
if (m_refs.empty())
|
||||
return;
|
||||
|
||||
_LeakDebug(plFormat(" {} objects leaked...\n", m_refs.size()).c_str());
|
||||
for (hsRefCnt *ref : m_refs) {
|
||||
_LeakDebug(plFormat(" 0x{_08x} {}: {} refs remain\n",
|
||||
(uintptr_t)ref, typeid(*ref).name(), ref->RefCnt()).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
static _RefCountLeakCheck *_instance()
|
||||
{
|
||||
static _RefCountLeakCheck s_instance;
|
||||
return &s_instance;
|
||||
}
|
||||
|
||||
static void add(hsRefCnt *ref)
|
||||
{
|
||||
_RefCountLeakCheck *this_p = _instance();
|
||||
std::lock_guard<std::mutex> lock(this_p->m_mutex);
|
||||
++this_p->m_added;
|
||||
this_p->m_refs.insert(ref);
|
||||
}
|
||||
|
||||
static void del(hsRefCnt *ref)
|
||||
{
|
||||
_RefCountLeakCheck *this_p = _instance();
|
||||
std::lock_guard<std::mutex> lock(this_p->m_mutex);
|
||||
++this_p->m_removed;
|
||||
this_p->m_refs.erase(ref);
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
hsRefCnt::hsRefCnt(int initRefs)
|
||||
: fRefCnt(initRefs)
|
||||
{
|
||||
#if (REFCOUNT_DEBUGGING == REFCOUNT_DBG_LEAKS) || (REFCOUNT_DEBUGGING == REFCOUNT_DBG_ALL)
|
||||
_RefCountLeakCheck::add(this);
|
||||
#endif
|
||||
}
|
||||
|
||||
hsRefCnt::~hsRefCnt()
|
||||
{
|
||||
#ifdef HS_DEBUGGING
|
||||
hsThrowIfFalse(fRefCnt == 1);
|
||||
#endif
|
||||
|
||||
#if (REFCOUNT_DEBUGGING == REFCOUNT_DBG_LEAKS) || (REFCOUNT_DEBUGGING == REFCOUNT_DBG_ALL)
|
||||
_RefCountLeakCheck::del(this);
|
||||
#endif
|
||||
}
|
||||
|
||||
void hsRefCnt::UnRef()
|
||||
void hsRefCnt::UnRef(const char* tag)
|
||||
{
|
||||
#ifdef HS_DEBUGGING
|
||||
hsThrowIfFalse(fRefCnt >= 1);
|
||||
#endif
|
||||
|
||||
#if (REFCOUNT_DEBUGGING == REFCOUNT_DBG_REFS) || (REFCOUNT_DEBUGGING == REFCOUNT_DBG_ALL)
|
||||
if (tag)
|
||||
DEBUG_MSG("Dec %p %s: %u", this, tag, fRefCnt - 1);
|
||||
else
|
||||
DEBUG_MSG("Dec %p: %u", this, fRefCnt - 1);
|
||||
#endif
|
||||
|
||||
if (fRefCnt == 1) // don't decrement if we call delete
|
||||
delete this;
|
||||
else
|
||||
--fRefCnt;
|
||||
}
|
||||
|
||||
hsAtomicRefCnt::~hsAtomicRefCnt()
|
||||
void hsRefCnt::Ref(const char* tag)
|
||||
{
|
||||
#ifdef HS_DEBUGGING
|
||||
hsThrowIfFalse(fRefCnt == 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
void hsAtomicRefCnt::UnRef(const char* tag)
|
||||
{
|
||||
#ifdef HS_DEBUGGING
|
||||
hsThrowIfFalse(fRefCnt >= 1);
|
||||
#endif
|
||||
|
||||
#ifdef REFCOUNT_DEBUGGING
|
||||
#if (REFCOUNT_DEBUGGING == REFCOUNT_DBG_REFS) || (REFCOUNT_DEBUGGING == REFCOUNT_DBG_ALL)
|
||||
if (tag)
|
||||
DEBUG_MSG("Dec %p %s: %u", this, tag, prev - 1);
|
||||
DEBUG_MSG("Inc %p %s: %u", this, tag, fRefCnt + 1);
|
||||
else
|
||||
DEBUG_MSG("Dec %p: %u", this, prev - 1);
|
||||
#endif
|
||||
|
||||
if (fRefCnt == 1) // don't decrement if we call delete
|
||||
delete this;
|
||||
else
|
||||
--fRefCnt;
|
||||
}
|
||||
|
||||
void hsAtomicRefCnt::Ref(const char* tag)
|
||||
{
|
||||
#ifdef REFCOUNT_DEBUGGING
|
||||
if (tag)
|
||||
DEBUG_MSG("Inc %p %s: %u", this, tag, prev + 1);
|
||||
else
|
||||
DEBUG_MSG("Inc %p: %u", this, prev + 1);
|
||||
DEBUG_MSG("Inc %p: %u", this, fRefCnt + 1);
|
||||
#endif
|
||||
|
||||
++fRefCnt;
|
||||
}
|
||||
|
||||
void hsAtomicRefCnt::TransferRef(const char* oldTag, const char* newTag)
|
||||
void hsRefCnt::TransferRef(const char* oldTag, const char* newTag)
|
||||
{
|
||||
#ifdef REFCOUNT_DEBUGGING
|
||||
#if (REFCOUNT_DEBUGGING == REFCOUNT_DBG_REFS) || (REFCOUNT_DEBUGGING == REFCOUNT_DBG_ALL)
|
||||
DEBUG_MSG("Inc %p %s: (xfer)", this, newTag);
|
||||
DEBUG_MSG("Dec %p %s: (xfer)", this, oldTag);
|
||||
#endif
|
||||
|
@ -45,39 +45,12 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
#include <atomic>
|
||||
|
||||
class hsRefCnt {
|
||||
private:
|
||||
int fRefCnt;
|
||||
|
||||
public:
|
||||
hsRefCnt(int initRefs = 1) : fRefCnt(initRefs) {}
|
||||
virtual ~hsRefCnt();
|
||||
|
||||
inline int RefCnt() const { return fRefCnt; }
|
||||
void UnRef();
|
||||
inline void Ref() { ++fRefCnt; }
|
||||
};
|
||||
|
||||
#define hsRefCnt_SafeRef(obj) do { if (obj) (obj)->Ref(); } while (0)
|
||||
#define hsRefCnt_SafeUnRef(obj) do { if (obj) (obj)->UnRef(); } while (0)
|
||||
|
||||
#define hsRefCnt_SafeAssign(dst, src) \
|
||||
do { \
|
||||
hsRefCnt_SafeRef(src); \
|
||||
hsRefCnt_SafeUnRef(dst); \
|
||||
dst = src; \
|
||||
} while (0)
|
||||
|
||||
|
||||
// Thread-safe version. TODO: Evaluate whether this is fast enough to
|
||||
// merge with hsRefCnt above.
|
||||
class hsAtomicRefCnt
|
||||
{
|
||||
private:
|
||||
std::atomic<int> fRefCnt;
|
||||
|
||||
public:
|
||||
hsAtomicRefCnt(int initRefs = 1) : fRefCnt(initRefs) { }
|
||||
virtual ~hsAtomicRefCnt();
|
||||
hsRefCnt(int initRefs = 1);
|
||||
virtual ~hsRefCnt();
|
||||
|
||||
inline int RefCnt() const { return fRefCnt; }
|
||||
void UnRef(const char* tag = nullptr);
|
||||
@ -85,6 +58,81 @@ public:
|
||||
|
||||
// Useless, but left here for debugging compatibility with AtomicRef
|
||||
void TransferRef(const char* oldTag, const char* newTag);
|
||||
|
||||
|
||||
// The stored reference count of an hsRefCnt-derived object should never
|
||||
// be copied! Therefore, if you want a copyable hsRefCnt-based class, you
|
||||
// should implement your own copy constructor / assignment operator.
|
||||
hsRefCnt(const hsRefCnt &) = delete;
|
||||
hsRefCnt &operator=(const hsRefCnt &) = delete;
|
||||
};
|
||||
|
||||
#define hsRefCnt_SafeRef(obj) do { if (obj) (obj)->Ref(); } while (0)
|
||||
#define hsRefCnt_SafeUnRef(obj) do { if (obj) (obj)->UnRef(); } while (0)
|
||||
|
||||
#define hsRefCnt_SafeAssign(dst, src) \
|
||||
do { \
|
||||
hsRefCnt_SafeRef(src); \
|
||||
hsRefCnt_SafeUnRef(dst); \
|
||||
dst = src; \
|
||||
} while (0)
|
||||
|
||||
|
||||
template <class _Ref>
|
||||
class hsRef
|
||||
{
|
||||
public:
|
||||
hsRef() : fObj(nullptr) { }
|
||||
hsRef(nullptr_t) : fObj(nullptr) { }
|
||||
hsRef(_Ref *obj) : fObj(obj) { if (fObj) fObj->Ref(); }
|
||||
hsRef(const hsRef<_Ref> ©) : fObj(copy.fObj) { if (fObj) fObj->Ref(); }
|
||||
hsRef(hsRef<_Ref> &&move) : fObj(move.fObj) { move.fObj = nullptr; }
|
||||
|
||||
~hsRef() { if (fObj) fObj->UnRef(); }
|
||||
|
||||
hsRef<_Ref> &operator=(_Ref *obj)
|
||||
{
|
||||
if (obj)
|
||||
obj->Ref();
|
||||
if (fObj)
|
||||
fObj->UnRef();
|
||||
fObj = obj;
|
||||
return *this;
|
||||
}
|
||||
hsRef<_Ref> &operator=(const hsRef<_Ref> ©) { return operator=(copy.fObj); }
|
||||
|
||||
hsRef<_Ref> &operator=(hsRef<_Ref> &&move)
|
||||
{
|
||||
if (fObj)
|
||||
fObj->UnRef();
|
||||
fObj = move.fObj;
|
||||
move.fObj = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
hsRef<_Ref> &operator=(nullptr_t)
|
||||
{
|
||||
if (fObj)
|
||||
fObj->UnRef();
|
||||
fObj = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator==(const hsRef<_Ref> &other) const { return fObj == other.fObj; }
|
||||
bool operator!=(const hsRef<_Ref> &other) const { return fObj != other.fObj; }
|
||||
bool operator> (const hsRef<_Ref> &other) const { return fObj > other.fObj; }
|
||||
bool operator< (const hsRef<_Ref> &other) const { return fObj < other.fObj; }
|
||||
bool operator>=(const hsRef<_Ref> &other) const { return fObj >= other.fObj; }
|
||||
bool operator<=(const hsRef<_Ref> &other) const { return fObj <= other.fObj; }
|
||||
bool operator==(_Ref *other) const { return fObj == other; }
|
||||
bool operator!=(_Ref *other) const { return fObj != other; }
|
||||
|
||||
_Ref &operator*() const { return *fObj; }
|
||||
_Ref *const operator->() const { return fObj; }
|
||||
operator _Ref *const() const { return fObj; }
|
||||
|
||||
private:
|
||||
_Ref *fObj;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
Reference in New Issue
Block a user