From 972cfa0d39cb83f06259942b2b10ee319568911f Mon Sep 17 00:00:00 2001 From: dean11 Date: Wed, 27 Nov 2013 21:12:37 +0100 Subject: [PATCH 1/3] Fixed bugs with custom loading --- Code/Misc/Resource/Loaders/ByteLoader.cpp | 2 +- Code/Misc/Resource/Loaders/CustomLoader.cpp | 33 ++++++++--- Code/Misc/Resource/OResource.cpp | 10 ++-- Code/Misc/Resource/OResource.h | 32 +++++++--- Code/Misc/Resource/OResourceHandler.cpp | 65 +++++++++++++++++---- Code/Misc/Resource/OysterResource.h | 51 +++++++++++++--- 6 files changed, 150 insertions(+), 43 deletions(-) diff --git a/Code/Misc/Resource/Loaders/ByteLoader.cpp b/Code/Misc/Resource/Loaders/ByteLoader.cpp index 622d3a71..b20364ff 100644 --- a/Code/Misc/Resource/Loaders/ByteLoader.cpp +++ b/Code/Misc/Resource/Loaders/ByteLoader.cpp @@ -152,7 +152,7 @@ OResource* OResource::ByteLoader(const wchar_t filename[], ResourceType type, OR if(!old) { - resource = new OResource((OHRESOURCE)data, type, (sizeof(char) * sOut.size()), sizeof(char), filename); + resource = new OResource((OHRESOURCE&)data, type, (sizeof(char) * sOut.size()), sizeof(char), filename); } else { diff --git a/Code/Misc/Resource/Loaders/CustomLoader.cpp b/Code/Misc/Resource/Loaders/CustomLoader.cpp index 312c4c53..1e030a6b 100644 --- a/Code/Misc/Resource/Loaders/CustomLoader.cpp +++ b/Code/Misc/Resource/Loaders/CustomLoader.cpp @@ -12,34 +12,49 @@ using namespace Oyster::Resource; OResource* OResource::CustomLoader(const wchar_t filename[], CustomLoadFunction fnc) { - const CustomData &data = fnc(filename); + CustomData data; + memset(&data, 0, sizeof(CustomData)); - if(!data.loadedData) return 0; - if(!data.resourceUnloadFnc) return 0; + fnc(filename, data); + + if(!data.loadedData) + { + return 0; + } + if(!data.resourceUnloadFnc) + { + return 0; + } + /** For some wierd reason that i don't understand when trying to send data.loadedData directly as a + * parameter to OResource constructor, the value is changed when it arrives in the constructor. + * Doing it like this, storing in a temporary variable, the value stays correct. (What the fuck! I must be overloking something...)*/ + //OHRESOURCE temp = data.loadedData; + OResource *resource = new OResource(data.loadedData, ResourceType_UNKNOWN, 0, 0, filename); - OResource *resource = new OResource((OHRESOURCE)data.loadedData, ResourceType_UNKNOWN, 0, 0, filename); - resource->customData = new CustomResourceData(); resource->customData->unloadingFunction = data.resourceUnloadFnc; - resource->resourceData = (OHRESOURCE)data.loadedData; resource->customData->loadingFunction = fnc; return resource; } void OResource::CustomUnloader() { - this->customData->unloadingFunction((void*)this->resourceData); + this->customData->unloadingFunction(this->resourceData); } OResource* OResource::CustomReloader() { CustomUnloader(); - const CustomData &data = this->customData->loadingFunction(this->resourceFilename.c_str()); + CustomData data; + memset(&data, 0, sizeof(CustomData)); + + this->customData->loadingFunction(this->resourceFilename.c_str(), data); this->resourceData = (OHRESOURCE)data.loadedData; if(data.resourceUnloadFnc) + { this->customData->unloadingFunction = data.resourceUnloadFnc; - + } return this; } diff --git a/Code/Misc/Resource/OResource.cpp b/Code/Misc/Resource/OResource.cpp index 4311669f..e2aab644 100644 --- a/Code/Misc/Resource/OResource.cpp +++ b/Code/Misc/Resource/OResource.cpp @@ -7,17 +7,19 @@ using namespace Oyster::Resource; OResource::OResource(OHRESOURCE handle, ResourceType type, size_t resourceSize, size_t elementSize, ::std::wstring filename) - : resourceData (handle) - , resourceFilename (filename) + : resourceFilename (filename) , resourceSize (resourceSize) , resourceElementSize (elementSize) , resourceType (type) , customData (0) { - + resourceData = handle; } OResource::~OResource() -{} +{ + delete this->customData; + this->customData = 0; +} OResource* OResource::Load (const wchar_t filename[], ResourceType type) diff --git a/Code/Misc/Resource/OResource.h b/Code/Misc/Resource/OResource.h index c0e32ba5..a0573c92 100644 --- a/Code/Misc/Resource/OResource.h +++ b/Code/Misc/Resource/OResource.h @@ -27,19 +27,33 @@ namespace Oyster virtual~ OResource(); inline ResourceType GetResourceType() const - { return this->resourceType; } + { + return this->resourceType; + } inline const wchar_t* GetResourceFilename() const - { return this->resourceFilename.c_str(); } + { + return this->resourceFilename.c_str(); + } inline OHRESOURCE GetResourceHandle() const - { return this->resourceData; } + { + return this->resourceData; + } inline unsigned long long GetResourceSize() const - { return this->resourceSize; } + { + return this->resourceSize; + } inline unsigned long long GetResourceElementSize() const - { return this->resourceElementSize; } + { + return this->resourceElementSize; + } inline unsigned int GetResourceID() const - { return this->resourceID; } - inline void SetResourceID(unsigned int id) - { this->resourceID = id; } + { + return this->resourceID; + } + inline void SetResourceID(int id) + { + this->resourceID = id; + } public: static OResource* Load (const wchar_t filename[], ResourceType type); @@ -63,7 +77,7 @@ namespace Oyster size_t resourceSize; size_t resourceElementSize; ::std::wstring resourceFilename; - unsigned int resourceID; + int resourceID; CustomResourceData *customData; }; diff --git a/Code/Misc/Resource/OResourceHandler.cpp b/Code/Misc/Resource/OResourceHandler.cpp index 9d911875..21653d4e 100644 --- a/Code/Misc/Resource/OResourceHandler.cpp +++ b/Code/Misc/Resource/OResourceHandler.cpp @@ -43,7 +43,7 @@ OHRESOURCE OysterResource::LoadResource(const wchar_t* filename, ResourceType ty return resourceData->GetResourceHandle(); } -OHRESOURCE OysterResource::LoadResource(const wchar_t filename[], CustomLoadFunction loadFnc, unsigned int CustomId) +OHRESOURCE OysterResource::LoadResource(const wchar_t filename[], CustomLoadFunction loadFnc, int CustomId) { if(!filename) return 0; if(!loadFnc) return 0; @@ -67,14 +67,14 @@ OHRESOURCE OysterResource::LoadResource(const wchar_t filename[], CustomLoadFunc return (OHRESOURCE)resourceData->GetResourceHandle(); } -OHRESOURCE ReloadResource(const wchar_t filename[]) +OHRESOURCE OysterResource::ReloadResource(const wchar_t filename[]) { OResource *resourceData = resourcePrivate.FindResource(filename); if(!resourceData) return 0; //The resource has not been loaded return OResource::Reload(resourceData)->GetResourceHandle(); } -OHRESOURCE ReloadResource(OHRESOURCE resource) +OHRESOURCE OysterResource::ReloadResource(OHRESOURCE resource) { OResource *resourceData = resourcePrivate.FindResource(resource); if(!resourceData) return 0; //The resource has not been loaded @@ -89,12 +89,13 @@ void OysterResource::Clean() for (i; i != last; i++) { - if(OResource::Release(i->second)) - { - const wchar_t* temp = i->second->GetResourceFilename(); - delete resourcePrivate.resources[temp]; - resourcePrivate.resources.erase(temp); - } + //Remove all the references + while (!OResource::Release(i->second)); + + const wchar_t* temp = i->second->GetResourceFilename(); + delete resourcePrivate.resources[temp]; + resourcePrivate.resources.erase(temp); + } } void OysterResource::ReleaseResource(const OHRESOURCE& resourceData) @@ -110,6 +111,19 @@ void OysterResource::ReleaseResource(const OHRESOURCE& resourceData) } } } +void OysterResource::ReleaseResource(const wchar_t filename[]) +{ + OResource* t = resourcePrivate.FindResource(filename); + if(t) + { + if(OResource::Release(t)) + { + const wchar_t* temp = t->GetResourceFilename(); + delete resourcePrivate.resources[temp]; + resourcePrivate.resources.erase(temp); + } + } +} void OysterResource::SetResourceId (const OHRESOURCE& resourceData, unsigned int id) { @@ -117,13 +131,27 @@ void OysterResource::SetResourceId (const OHRESOURCE& resourceData, unsigned int if(t) t->SetResourceID(id); } +void OysterResource::SetResourceId(const wchar_t c[], unsigned int id) +{ + OResource* t = resourcePrivate.FindResource(c); + + if(t) t->SetResourceID(id); +} ResourceType OysterResource::GetResourceType (const OHRESOURCE& resourceData) { OResource* t = resourcePrivate.FindResource(resourceData); if(t) return t->GetResourceType(); - return ResourceType_UNKNOWN; + return ResourceType_INVALID; +} +ResourceType OysterResource::GetResourceType (const wchar_t c[]) +{ + OResource* t = resourcePrivate.FindResource(c); + + if(t) return t->GetResourceType(); + + return ResourceType_INVALID; } const wchar_t* OysterResource::GetResourceFilename (const OHRESOURCE& resourceData) { @@ -133,7 +161,15 @@ const wchar_t* OysterResource::GetResourceFilename (const OHRESOURCE& resourceDa return 0; } -unsigned int OysterResource::GetResourceId (const OHRESOURCE& resourceData) +OHRESOURCE OysterResource::GetResourceHandle(const wchar_t filename[]) +{ + OResource* t = resourcePrivate.FindResource(filename); + + if(t) return t->GetResourceHandle(); + + return 0; +} +int OysterResource::GetResourceId (const OHRESOURCE& resourceData) { OResource* t = resourcePrivate.FindResource(resourceData); @@ -141,7 +177,14 @@ unsigned int OysterResource::GetResourceId (const OHRESOURCE& resourceData) return -1; } +int OysterResource::GetResourceId(const wchar_t c[]) +{ + OResource* t = resourcePrivate.FindResource(c); + if(t) return t->GetResourceID(); + + return -1; +} OResource* ResourcePrivate::FindResource(const OHRESOURCE& h) const diff --git a/Code/Misc/Resource/OysterResource.h b/Code/Misc/Resource/OysterResource.h index 16d5122d..8fc0e560 100644 --- a/Code/Misc/Resource/OysterResource.h +++ b/Code/Misc/Resource/OysterResource.h @@ -12,11 +12,11 @@ namespace Oyster { struct CustomData; /** A Resource handle representing various resources */ - typedef unsigned long OHRESOURCE; + typedef void* OHRESOURCE; /** Typedef on a fuction required for custom unloading */ typedef void(*CustomUnloadFunction)(void* loadedData); /** Typedef on a fuction required for custom loading */ - typedef const CustomData&(*CustomLoadFunction)(const wchar_t filename[]); + typedef void(*CustomLoadFunction)(const wchar_t filename[], CustomData& outData); /** An enum class representing all avalible resources that is supported. */ enum ResourceType @@ -31,15 +31,14 @@ namespace Oyster ResourceType_COUNT, /**< Not used. */ ResourceType_UNKNOWN = -1, /**< Handle can be interpeted as void* */ + ResourceType_INVALID = -2, /**< Invalid or non existing resource */ }; - /** A struct to return when doing a custom resource Load - * By loading this way you are handing over the ownership to the resource loaded. - */ + /** A struct to fill when doing a custom resource Load. */ struct CustomData { - void* loadedData; /// Date: Wed, 27 Nov 2013 21:47:32 +0100 Subject: [PATCH 2/3] Fixed bugs in the threading wrapper --- Code/Misc/Thread/OysterMutex.cpp | 5 - Code/Misc/Thread/OysterMutex.h | 2 - Code/Misc/Thread/OysterThread.h | 6 +- Code/Misc/Thread/OysterThread_Impl.cpp | 124 +++++++++++++++---------- Code/Misc/Utilities-InlineImpl.h | 17 ++-- Code/Misc/Utilities.h | 1 + 6 files changed, 86 insertions(+), 69 deletions(-) diff --git a/Code/Misc/Thread/OysterMutex.cpp b/Code/Misc/Thread/OysterMutex.cpp index a8dfd20f..089323ce 100644 --- a/Code/Misc/Thread/OysterMutex.cpp +++ b/Code/Misc/Thread/OysterMutex.cpp @@ -63,9 +63,4 @@ void OysterMutex::UnlockMutex() bool OysterMutex::IsTaken() { return !this->mutex.try_lock(); -} -void OysterMutex::Reset() -{ - if(!this->mutex.try_lock()) - this->mutex.unlock(); } \ No newline at end of file diff --git a/Code/Misc/Thread/OysterMutex.h b/Code/Misc/Thread/OysterMutex.h index b36585c1..18282499 100644 --- a/Code/Misc/Thread/OysterMutex.h +++ b/Code/Misc/Thread/OysterMutex.h @@ -20,8 +20,6 @@ public: void UnlockMutex(); /** Returns true if mutex is taken */ bool IsTaken(); - /** This function resets resource locking */ - void Reset(); private: std::mutex mutex; diff --git a/Code/Misc/Thread/OysterThread.h b/Code/Misc/Thread/OysterThread.h index 873497ad..05a9f8ad 100644 --- a/Code/Misc/Thread/OysterThread.h +++ b/Code/Misc/Thread/OysterThread.h @@ -6,7 +6,6 @@ #define MISC_OYSTER_THREAD_H #include "IThreadObject.h" - namespace Oyster { namespace Thread @@ -23,11 +22,10 @@ namespace Oyster struct PrivateData; PrivateData *privateData; - OysterThread(const OysterThread& original); - const OysterThread& operator=(const OysterThread& original); - public: OysterThread(); + OysterThread(const OysterThread& original); + const OysterThread& operator=(const OysterThread& original); virtual~OysterThread(); OYSTER_THREAD_ERROR Create(IThreadObject* worker, bool start); diff --git a/Code/Misc/Thread/OysterThread_Impl.cpp b/Code/Misc/Thread/OysterThread_Impl.cpp index 171c8aa9..9b01e6d5 100644 --- a/Code/Misc/Thread/OysterThread_Impl.cpp +++ b/Code/Misc/Thread/OysterThread_Impl.cpp @@ -7,6 +7,7 @@ #include "..\Utilities.h" #include #include +#include using namespace Oyster::Thread; using namespace Utility::DynamicMemory::SmartPointer; @@ -24,24 +25,23 @@ using namespace Utility::DynamicMemory::SmartPointer; OYSTER_THREAD_STATE_RUNNING, OYSTER_THREAD_STATE_PAUSED, OYSTER_THREAD_STATE_STOPED, - OYSTER_THREAD_STATE_TERMINATED, OYSTER_THREAD_STATE_DEAD, }; - //TODO: Add a threadStartPackage struct that contains all the necasary data to fire of a thread + struct ThreadData { - OYSTER_THREAD_STATE state; // workerThread; // state; // workerThread; // msec; //callingThread; threadData->state = OYSTER_THREAD_STATE_STOPED; } + PrivateData(const PrivateData& o) + { + threadData = o.threadData; + } ~PrivateData() { //@todo TODO: Make detatch avalible. @@ -70,35 +74,46 @@ using namespace Utility::DynamicMemory::SmartPointer; #pragma endregion - +int tempId = 0; +std::vector IDS; static void ThreadingFunction(StdSmartPointer &origin) { + bool shouldContinue; StdSmartPointer w = origin; theBegining: - while(w->state == OYSTER_THREAD_STATE_STOPED); - w->mutexLock.LockMutex(); - w->owner->ThreadEntry(); - w->mutexLock.UnlockMutex(); + while(w->state == OYSTER_THREAD_STATE_STOPED) + { + std::this_thread::yield(); + } + +// w->mutexLock.LockMutex(); + if(w->owner) + { + w->owner->ThreadEntry(); + } +// w->mutexLock.UnlockMutex(); while (w->state != OYSTER_THREAD_STATE_STOPED && w->state != OYSTER_THREAD_STATE_DEAD) { - - w->mutexLock.LockMutex(); +// w->mutexLock.LockMutex(); { - shouldContinue = w->owner->DoWork(); + if(w->owner) + { + shouldContinue = w->owner->DoWork(); + } } - w->mutexLock.UnlockMutex(); +// w->mutexLock.UnlockMutex(); if(!shouldContinue) { goto theEnd; } - if(w->state == OYSTER_THREAD_STATE_TERMINATED) + if(w->state == OYSTER_THREAD_STATE_DEAD) { - return; + goto theEnd; } else if(w->state == OYSTER_THREAD_STATE_RESET) { @@ -109,19 +124,26 @@ theBegining: std::this_thread::sleep_for(std::chrono::milliseconds(w->msec)); } - while (w->state == OYSTER_THREAD_STATE_PAUSED); + while (w->state == OYSTER_THREAD_STATE_PAUSED) + { + std::this_thread::yield(); + } } if(w->state == OYSTER_THREAD_STATE_DEAD) { + w->workerThread->detach(); return; } theEnd: - w->mutexLock.LockMutex(); - w->owner->ThreadExit(); - w->mutexLock.UnlockMutex(); +// w->mutexLock.LockMutex(); + if(w->owner) + { + w->owner->ThreadExit(); + } +// w->mutexLock.UnlockMutex(); w->state = OYSTER_THREAD_STATE_DEAD; } @@ -130,6 +152,14 @@ OysterThread::OysterThread() { this->privateData = new PrivateData(); } +OysterThread::OysterThread(const OysterThread& original) +{ + this->privateData = new PrivateData(*original.privateData); +} +const OysterThread& OysterThread::operator=(const OysterThread& original) +{ + return *this; +} OysterThread::~OysterThread() { delete this->privateData; @@ -153,30 +183,33 @@ OYSTER_THREAD_ERROR OysterThread::Create(IThreadObject* worker, bool start) if(start) { - //@todo TODO: No need to lock since the other thread end is only reading this value. Worst case scenario is n lost cycles. this->privateData->threadData->state = OYSTER_THREAD_STATE_RUNNING; } return OYSTER_THREAD_ERROR_SUCCESS; } OYSTER_THREAD_ERROR OysterThread::Start() { + if(!this->privateData->threadData->owner) + return OYSTER_THREAD_ERROR_FAILED; if(!this->privateData->threadData->workerThread) return OYSTER_THREAD_ERROR_FAILED; + if(this->privateData->threadData->state == OYSTER_THREAD_STATE_DEAD) + return OYSTER_THREAD_ERROR_FAILED; this->privateData->threadData->state = OYSTER_THREAD_STATE_RUNNING; return OYSTER_THREAD_ERROR_SUCCESS; } void OysterThread::Stop() { - this->privateData->threadData->mutexLock.LockMutex(); - this->privateData->threadData->state = OYSTER_THREAD_STATE_STOPED; - this->privateData->threadData->mutexLock.UnlockMutex(); + //this->privateData->threadData->mutexLock.LockMutex(); + this->privateData->threadData->state = OYSTER_THREAD_STATE_STOPED; + //this->privateData->threadData->mutexLock.UnlockMutex(); } void OysterThread::Pause() { - this->privateData->threadData->mutexLock.LockMutex(); - this->privateData->threadData->state = OYSTER_THREAD_STATE_PAUSED; - this->privateData->threadData->mutexLock.UnlockMutex(); + //this->privateData->threadData->mutexLock.LockMutex(); + this->privateData->threadData->state = OYSTER_THREAD_STATE_PAUSED; + //this->privateData->threadData->mutexLock.UnlockMutex(); } void OysterThread::Pause(int msec) { @@ -187,39 +220,34 @@ void OysterThread::Pause(int msec) } else { - this->privateData->threadData->mutexLock.LockMutex(); - this->privateData->threadData->state = OYSTER_THREAD_STATE_PAUSED; - this->privateData->threadData->msec = msec; - this->privateData->threadData->mutexLock.UnlockMutex(); + //this->privateData->threadData->mutexLock.LockMutex(); + this->privateData->threadData->state = OYSTER_THREAD_STATE_PAUSED; + this->privateData->threadData->msec = msec; + //this->privateData->threadData->mutexLock.UnlockMutex(); } } void OysterThread::Resume() { - this->privateData->threadData->mutexLock.LockMutex(); +// this->privateData->threadData->mutexLock.LockMutex(); this->privateData->threadData->state = OYSTER_THREAD_STATE_RUNNING; - this->privateData->threadData->mutexLock.UnlockMutex(); +// this->privateData->threadData->mutexLock.UnlockMutex(); } OYSTER_THREAD_ERROR OysterThread::Reset(IThreadObject* worker) { - this->privateData->threadData->mutexLock.LockMutex(); +// this->privateData->threadData->mutexLock.LockMutex(); if(worker) { this->privateData->threadData->owner = worker; } this->privateData->threadData->callingThread = std::this_thread::get_id(); this->privateData->threadData->msec = 0; - this->privateData->threadData->mutexLock.UnlockMutex(); +// this->privateData->threadData->mutexLock.UnlockMutex(); return OYSTER_THREAD_ERROR_SUCCESS; } void OysterThread::Terminate() { - delete this->privateData->threadData->workerThread; - this->privateData->threadData->mutexLock.Reset(); - this->privateData->threadData->workerThread = 0; - this->privateData->threadData->callingThread = std::thread::id(); - this->privateData->threadData->msec = 0; - this->privateData->threadData->state = OYSTER_THREAD_STATE_STOPED; + this->privateData->threadData->state = OYSTER_THREAD_STATE_DEAD; } void OysterThread::Wait() { @@ -250,4 +278,4 @@ bool OysterThread::IsActive() return false; } - \ No newline at end of file + diff --git a/Code/Misc/Utilities-InlineImpl.h b/Code/Misc/Utilities-InlineImpl.h index b8c4c6da..0cd164d8 100644 --- a/Code/Misc/Utilities-InlineImpl.h +++ b/Code/Misc/Utilities-InlineImpl.h @@ -165,8 +165,7 @@ namespace Utility namespace SmartPointer { - template - void StdSmartPointer::Destroy() + template void StdSmartPointer::Destroy() { delete this->_rc; this->_rc = NULL; @@ -200,7 +199,7 @@ namespace Utility if (this != &p) { //Last to go? - if(this->_rc && this->_rc->Release() == 0) + if(this->_rc && this->_rc->Decref() == 0) { //Call child specific Destroy(); @@ -208,7 +207,7 @@ namespace Utility this->_ptr = p._ptr; this->_rc = p._rc; - this->_rc->Add(); + this->_rc->Incref(); } return *this; } @@ -254,16 +253,14 @@ namespace Utility { return this->_ptr; } - - /** - * Returns the connected pointer */ + template inline StdSmartPointer::operator bool() + { + return (this->_ptr != 0); + } template inline T* StdSmartPointer::Get() { return this->_ptr; } - - /** Checks if the pointer is valid (not NULL) - Returns true for valid, else false. */ template inline bool StdSmartPointer::IsValid() { return (this->_ptr != NULL) ? true : false; diff --git a/Code/Misc/Utilities.h b/Code/Misc/Utilities.h index e1582697..8eaf18f4 100644 --- a/Code/Misc/Utilities.h +++ b/Code/Misc/Utilities.h @@ -151,6 +151,7 @@ namespace Utility T& operator* (); T* operator-> (); operator T* (); + operator bool(); /** * Returns the connected pointer */ From 5eec570768da886625ebce6bad60a7bfb74a4941 Mon Sep 17 00:00:00 2001 From: dean11 Date: Wed, 27 Nov 2013 22:39:49 +0100 Subject: [PATCH 3/3] Added an atomic to the reference counter for thread saftey --- Code/Misc/Utilities.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Code/Misc/Utilities.h b/Code/Misc/Utilities.h index 8eaf18f4..f34907de 100644 --- a/Code/Misc/Utilities.h +++ b/Code/Misc/Utilities.h @@ -12,6 +12,7 @@ #include #include #include +#include namespace Utility { @@ -110,12 +111,12 @@ namespace Utility struct ReferenceCount { private: - int count; + std::atomic count; public: ReferenceCount() :count(0) { } - ReferenceCount(const ReferenceCount& o) { count = o.count; } - inline const ReferenceCount& operator=(const ReferenceCount& o) { count = o.count; return *this;} + ReferenceCount(const ReferenceCount& o) { count.store(o.count); } + inline const ReferenceCount& operator=(const ReferenceCount& o) { count.store(o.count); return *this;} inline void Incref() { this->count++; } inline void Incref(int c) { this->count += c; } inline int Decref() { return --this->count;}