From 01440621269d7167715f85f6720236b2cec6c50f Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sun, 25 Aug 2013 11:59:44 -0700 Subject: [PATCH] Introduce NameHashSet (bug 5884 part 1, r=ds). --- core/logic/GameConfigs.cpp | 12 ++-- core/logic/GameConfigs.h | 10 ++- public/amtl/am-hashset.h | 126 ++++++++++++++++++++++++++++++++ public/sm_namehashset.h | 143 +++++++++++++++++++++++++++++++++++++ 4 files changed, 281 insertions(+), 10 deletions(-) create mode 100644 public/amtl/am-hashset.h create mode 100644 public/sm_namehashset.h diff --git a/core/logic/GameConfigs.cpp b/core/logic/GameConfigs.cpp index 393dba9d..b577410a 100644 --- a/core/logic/GameConfigs.cpp +++ b/core/logic/GameConfigs.cpp @@ -981,12 +981,10 @@ CGameConfig::AddressConf::AddressConf(char *sigName, unsigned sigLength, unsigne SendProp *CGameConfig::GetSendProp(const char *key) { - SendProp **pProp; - - if ((pProp = m_Props.retrieve(key)) == NULL) + SendProp *prop; + if (!m_Props.retrieve(key, &prop)) return NULL; - - return *pProp; + return prop; } bool CGameConfig::GetMemSig(const char *key, void **addr) @@ -1042,11 +1040,9 @@ bool GameConfigManager::LoadGameConfigFile(const char *file, IGameConfig **_pCon #endif CGameConfig *pConfig; - CGameConfig **ppConfig; - if ((ppConfig = m_Lookup.retrieve(file)) != NULL) + if (m_Lookup.retrieve(file, &pConfig)) { - pConfig = *ppConfig; pConfig->AddRef(); *_pConfig = pConfig; return true; diff --git a/core/logic/GameConfigs.h b/core/logic/GameConfigs.h index 3b83bd57..fb5486ac 100644 --- a/core/logic/GameConfigs.h +++ b/core/logic/GameConfigs.h @@ -39,6 +39,7 @@ #include #include #include +#include using namespace SourceMod; using namespace SourceHook; @@ -69,12 +70,17 @@ public: //IGameConfig SendProp *GetSendProp(const char *key); bool GetMemSig(const char *key, void **addr); bool GetAddress(const char *key, void **addr); +public: //NameHashSet + static inline bool matches(const char *key, const CGameConfig *value) + { + return strcmp(key, value->m_File) == 0; + } private: ke::AutoPtr m_pStrings; char m_File[PLATFORM_MAX_PATH]; char m_CurFile[PLATFORM_MAX_PATH]; StringHashMap m_Offsets; - KTrie m_Props; + StringHashMap m_Props; StringHashMap m_Keys; StringHashMap m_Sigs; /* Parse states */ @@ -139,7 +145,7 @@ public: //SMGlobalClass public: void RemoveCachedConfig(CGameConfig *config); private: - KTrie m_Lookup; + NameHashSet m_Lookup; public: StringHashMap m_customHandlers; }; diff --git a/public/amtl/am-hashset.h b/public/amtl/am-hashset.h new file mode 100644 index 00000000..6edbdea1 --- /dev/null +++ b/public/amtl/am-hashset.h @@ -0,0 +1,126 @@ +// 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_hashmap_h_ +#define _include_amtl_hashmap_h_ + +#include + +namespace ke { + +// Template parameters: +// +// K - Key type. +// HashPolicy - A struct with a hash and comparator function for each lookup type: +// static uint32_t hash(const Type &value); +// static bool matches(const Type &value, const K &key); +// +// Like HashMap and HashTable, init() must be called to construct the set. +template +class HashSet : public AllocPolicy +{ + struct Policy { + typedef K Payload; + + template + static uint32_t hash(const Lookup &key) { + return HashPolicy::hash(key); + } + + template + static bool matches(const Lookup &key, const Payload &payload) { + return HashPolicy::matches(key, payload); + } + }; + + typedef HashTable Internal; + + public: + HashSet(AllocPolicy ap = AllocPolicy()) + : table_(ap) + { + } + + // capacity must be a power of two. + bool init(size_t capacity = 16) { + return table_.init(capacity); + } + + typedef typename Internal::Result Result; + typedef typename Internal::Insert Insert; + + template + Result find(const Lookup &key) { + return table_.find(key); + } + + template + Insert findForAdd(const Lookup &key) { + return table_.findForAdd(key); + } + + template + void removeIfExists(const Lookup &key) { + return table_.remove(key); + } + + void remove(Result &r) { + table_.remove(r); + } + + // The map must not have been mutated in between findForAdd() and add(). + // The Insert object is still valid after add() returns, however. + bool add(Insert &i, const K &key) { + return table_.add(i, key); + } + + // This can be used to avoid compiler constructed temporaries, since AMTL + // does not yet support move semantics. If you use this, the key and value + // must be set after. + bool add(Insert &i) { + return table_.add(i); + } + + void clear() { + table_.clear(); + } + + size_t estimateMemoryUse() const { + return table_.estimateMemoryUse(); + } + + private: + Internal table_; +}; + +} + +#endif // _include_amtl_hashset_h_ diff --git a/public/sm_namehashset.h b/public/sm_namehashset.h new file mode 100644 index 00000000..dc1e347a --- /dev/null +++ b/public/sm_namehashset.h @@ -0,0 +1,143 @@ +/** + * vim: set ts=4 sw=4 tw=99 noet : + * ============================================================================= + * SourceMod + * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#ifndef _include_sourcemod_namehashset_h_ +#define _include_sourcemod_namehashset_h_ + +/** + * @file sm_namehashset.h + * + * @brief Stores a set of uniquely named objects. + */ + +#include +#include +#include +#include "sm_stringhashmap.h" + +namespace SourceMod +{ + +// The HashPolicy type must have this method: +// static bool matches(const char *key, const T &value); +// +// Depending on what lookup types are used. +// +// If these members are available on T, then the HashPolicy type can be left +// default. It is okay to use |T *|, the functions will still be looked up +// on |T|. +template +class NameHashSet : public SystemAllocatorPolicy +{ + typedef detail::CharsAndLength CharsAndLength; + + // Default policy type: the two types are different. Use them directly. + template + struct Policy { + typedef KeyType Payload; + + static uint32_t hash(const CharsAndLength &key) + { + return key.hash(); + } + + static bool matches(const CharsAndLength &key, const KeyType &value) + { + return KeyPolicyType::matches(key.chars(), value); + } + }; + + // Specialization: the types are equal, and T is a pointer. Strip the + // pointer off so we can access T:: for match functions. + template + struct Policy + { + typedef KeyType *Payload; + + static uint32_t hash(const detail::CharsAndLength &key) + { + return key.hash(); + } + + static bool matches(const CharsAndLength &key, const KeyType *value) + { + return KeyType::matches(key.chars(), value); + } + }; + + typedef HashTable, SystemAllocatorPolicy> Internal; + +public: + NameHashSet() + { + if (!table_.init()) + this->reportOutOfMemory(); + } + + typedef typename Internal::Result Result; + typedef typename Internal::Insert Insert; + + bool retrieve(const char *aKey, T *value) + { + CharsAndLength key(aKey); + Result r = table_.find(aKey); + if (!r.found()) + return false; + *value = *r; + return true; + } + + bool insert(const char *aKey, const T &value) + { + CharsAndLength key(aKey); + Insert i = table_.findForAdd(key); + if (i.found()) + return false; + return table_.add(i, value); + } + + bool remove(const char *aKey) + { + CharsAndLength key(aKey); + Result r = table_.find(key); + if (!r.found()) + return false; + table_.remove(r); + return true; + } + +private: + Internal table_; +}; + +} + +#endif // _include_sourcemod_namehashset_h_