diff --git a/core/logic/GameConfigs.cpp b/core/logic/GameConfigs.cpp index a4b6c3dc7..434200261 100644 --- a/core/logic/GameConfigs.cpp +++ b/core/logic/GameConfigs.cpp @@ -121,7 +121,6 @@ CGameConfig::CGameConfig(const char *file, const char *engine) strncopy(m_File, file, sizeof(m_File)); m_pAddresses = new KTrie(); m_pStrings = new BaseStringTable(512); - m_RefCount = 0; m_CustomLevel = 0; m_CustomHandler = NULL; @@ -141,8 +140,7 @@ CGameConfig::CGameConfig(const char *file, const char *engine) CGameConfig::~CGameConfig() { - delete m_pAddresses; - delete m_pStrings; + g_GameConfigs.RemoveCachedConfig(this); } SMCResult CGameConfig::ReadSMC_NewSection(const SMCStates *states, const char *name) @@ -1009,17 +1007,6 @@ bool CGameConfig::GetMemSig(const char *key, void **addr) return true; } -void CGameConfig::IncRefCount() -{ - m_RefCount++; -} - -unsigned int CGameConfig::DecRefCount() -{ - m_RefCount--; - return m_RefCount; -} - GameConfigManager::GameConfigManager() { } @@ -1073,7 +1060,7 @@ bool GameConfigManager::LoadGameConfigFile(const char *file, IGameConfig **_pCon if ((ppConfig = m_Lookup.retrieve(file)) != NULL) { pConfig = *ppConfig; - pConfig->IncRefCount(); + pConfig->AddRef(); *_pConfig = pConfig; return true; } @@ -1090,22 +1077,14 @@ bool GameConfigManager::LoadGameConfigFile(const char *file, IGameConfig **_pCon m_cfgs.push_back(pConfig); m_Lookup.insert(file, pConfig); - pConfig->IncRefCount(); - *_pConfig = pConfig; - return retval; } void GameConfigManager::CloseGameConfigFile(IGameConfig *cfg) { CGameConfig *pConfig = (CGameConfig *)cfg; - - if (pConfig->DecRefCount() == 0) - { - m_Lookup.remove(pConfig->m_File); - delete pConfig; - } + pConfig->Release(); } extern Handle_t g_GameConfigsType; @@ -1155,3 +1134,8 @@ void GameConfigManager::AcquireLock() void GameConfigManager::ReleaseLock() { } + +void GameConfigManager::RemoveCachedConfig(CGameConfig *config) +{ + m_Lookup.remove(config->m_File); +} diff --git a/core/logic/GameConfigs.h b/core/logic/GameConfigs.h index c1db36556..5db6a00b5 100644 --- a/core/logic/GameConfigs.h +++ b/core/logic/GameConfigs.h @@ -1,5 +1,5 @@ /** - * vim: set ts=4 : + * vim: set ts=4 sw=4 tw=99 noet: * ============================================================================= * SourceMod * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. @@ -38,6 +38,7 @@ #include #include "sm_memtable.h" #include +#include using namespace SourceMod; using namespace SourceHook; @@ -46,7 +47,8 @@ class SendProp; class CGameConfig : public ITextListener_SMC, - public IGameConfig + public IGameConfig, + public ke::Refcounted { friend class GameConfigManager; public: @@ -67,18 +69,14 @@ public: //IGameConfig SendProp *GetSendProp(const char *key); bool GetMemSig(const char *key, void **addr); bool GetAddress(const char *key, void **addr); -public: - void IncRefCount(); - unsigned int DecRefCount(); private: - BaseStringTable *m_pStrings; + ke::AutoPtr m_pStrings; char m_File[PLATFORM_MAX_PATH]; char m_CurFile[PLATFORM_MAX_PATH]; KTrie m_Offsets; KTrie m_Props; KTrie m_Keys; KTrie m_Sigs; - unsigned int m_RefCount; /* Parse states */ int m_ParseState; unsigned int m_IgnoreLevel; @@ -112,7 +110,7 @@ private: char m_AddressSignature[64]; int m_AddressReadCount; int m_AddressRead[8]; - KTrie *m_pAddresses; + ke::AutoPtr > m_pAddresses; const char *m_pEngine; const char *m_pBaseEngine; }; @@ -138,6 +136,8 @@ public: //SMGlobalClass void OnSourceModStartup(bool late); void OnSourceModAllInitialized(); void OnSourceModAllShutdown(); +public: + void RemoveCachedConfig(CGameConfig *config); private: List m_cfgs; KTrie m_Lookup; diff --git a/public/amtl/am-refcounting.h b/public/amtl/am-refcounting.h new file mode 100644 index 000000000..b18f8d8b9 --- /dev/null +++ b/public/amtl/am-refcounting.h @@ -0,0 +1,290 @@ +// vim: set sts=8 ts=2 sw=2 tw=99 et: +// +// Copyright (C) 2013, David Anderson and AlliedModders LLC +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, this +// list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of AlliedModders LLC nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +#ifndef _include_amtl_refcounting_h_ +#define _include_amtl_refcounting_h_ + +#include + +namespace ke { + +template class Ref; + +// Holds a refcounted T without addrefing it. This is similar to PassRef<> +// below, but is intended only for freshly allocated objects which start +// with reference count 1, and we don't want to add an extra ref just by +// assigning to PassRef<> or Ref<>. +template +class Newborn +{ + public: + Newborn(const T &t) + : thing_(t) + { + } + + T release() const { + T temp = thing_; + thing_ = T(); + return temp; + } + + private: + mutable T thing_; +}; + +// When returning a value, we'd rather not be needlessly changing the refcount, +// so we have a special type to use for returns. +template +class PassRef +{ + public: + PassRef(T *thing) + : thing_(thing) + { + AddRef(); + } + PassRef() + : thing_(NULL) + { + } + + PassRef(const Newborn &other) + : thing_(other.release()) + { + // Don't addref, newborn means already addref'd. + } + + template + inline PassRef(const Ref &other); + + PassRef(const PassRef &other) + : thing_(other.release()) + { + } + template + PassRef(const PassRef &other) + : thing_(other.release()) + { + } + ~PassRef() + { + Release(); + } + + operator T &() { + return *thing_; + } + operator T *() const { + return thing_; + } + T *operator ->() const { + return operator *(); + } + T *operator *() const { + return thing_; + } + operator bool () const { + return !!thing_; + } + bool operator !() const { + return !thing_; + } + + T *release() const { + return ReturnAndVoid(thing_); + } + + template + PassRef &operator =(const PassRef &other) { + Release(); + thing_ = other.release(); + return *this; + } + + private: + // Disallowed operators. + PassRef &operator =(T *other); + PassRef &operator =(Newborn &other); + + void AddRef() { + if (thing_) + thing_->AddRef(); + } + void Release() { + if (thing_) + thing_->Release(); + } + + private: + mutable T *thing_; +}; + +// Classes which are refcounted should inherit from this. +template +class Refcounted +{ + public: + Refcounted() + : refcount_(1) + { + } + + void AddRef() { + refcount_++; + } + void Release() { + assert(refcount_ > 0); + if (--refcount_ == 0) + delete static_cast(this); + } + + protected: + ~Refcounted() { + } + + private: + uintptr_t refcount_; +}; + +// Simple class for automatic refcounting. +template +class Ref +{ + public: + Ref(T *thing) + : thing_(thing) + { + AddRef(); + } + + Ref() + : thing_(NULL) + { + } + + Ref(const Ref &other) + : thing_(other.thing_) + { + AddRef(); + } + template + Ref(const Ref &other) + : thing_(*other) + { + AddRef(); + } + Ref(const PassRef &other) + : thing_(other.release()) + { + } + template + Ref(const PassRef &other) + : thing_(other.release()) + { + } + Ref(const Newborn &other) + : thing_(other.release()) + { + } + ~Ref() + { + Release(); + } + + T *operator ->() const { + return operator *(); + } + T *operator *() const { + return thing_; + } + operator T *() { + return thing_; + } + operator bool () const { + return !!thing_; + } + bool operator !() const { + return !thing_; + } + + template + Ref &operator =(S *thing) { + Release(); + thing_ = thing; + AddRef(); + return *this; + } + + template + Ref &operator =(const PassRef &other) { + Release(); + thing_ = other.release(); + return *this; + } + + template + Ref &operator =(const Newborn &other) { + Release(); + thing_ = other.release(); + return *this; + } + + Ref &operator =(const Ref &other) { + Release(); + thing_ = other.thing_; + AddRef(); + return *this; + } + + private: + void AddRef() { + if (thing_) + thing_->AddRef(); + } + void Release() { + if (thing_) + thing_->Release(); + } + + protected: + T *thing_; +}; + +template template +PassRef::PassRef(const Ref &other) + : thing_(*other) +{ + AddRef(); +} + +} // namespace ke + +#endif // _include_amtl_refcounting_h_ +