From aaac0b9eb2aff131250b0b71b14349c6fa1bc76a Mon Sep 17 00:00:00 2001 From: Michael Flaherty Date: Tue, 10 Jul 2018 14:38:40 -0700 Subject: [PATCH] Individualize NameHashSet Hashing & Revisit #709 (#740) * Make mac/win lookups lowercase'd * Revert #709 & 81042cc * Adjust HashPolicy implementation across sourcemod Basically, in order to implement our own (actual) hash policy in `PluginSys.h`, we needed to remove the blanket implementation of `hash` that was used before. Now, each policy must implement `hash` along with `matches` in order to be used with `NameHashSet`. While this does force us to change every implementation of policies across the entirety of sourcemod, it allows core to use flexible implementations of `hash`. * Remove logic duplication * Improve lowercase checks --- core/ConVarManager.h | 5 +++++ core/EventManager.h | 4 ++++ core/HalfLife2.h | 14 ++++++++++++- core/logic/AdminCache.h | 4 ++++ core/logic/GameConfigs.h | 4 ++++ core/logic/HandleSys.h | 4 ++++ core/logic/Native.h | 5 +++++ core/logic/PluginSys.cpp | 31 +++------------------------- core/logic/PluginSys.h | 36 +++++++++++++++++++++++++++------ core/logic/RootConsoleMenu.h | 4 ++++ core/logic/smn_maplists.cpp | 4 ++++ core/smn_console.cpp | 4 ++++ extensions/clientprefs/cookie.h | 4 ++++ extensions/topmenus/TopMenu.h | 4 ++++ public/sm_namehashset.h | 12 ++++++----- 15 files changed, 99 insertions(+), 40 deletions(-) diff --git a/core/ConVarManager.h b/core/ConVarManager.h index 07dfdd35..f39cd295 100644 --- a/core/ConVarManager.h +++ b/core/ConVarManager.h @@ -43,6 +43,7 @@ #include #include "concmd_cleaner.h" #include "PlayerManager.h" +#include using namespace SourceHook; @@ -67,6 +68,10 @@ struct ConVarInfo { return strcmp(name, info->pVar->GetName()) == 0; } + static inline uint32_t hash(const detail::CharsAndLength &key) + { + return key.hash(); + } }; /** diff --git a/core/EventManager.h b/core/EventManager.h index bf7bd37b..1c8a1da5 100644 --- a/core/EventManager.h +++ b/core/EventManager.h @@ -77,6 +77,10 @@ struct EventHook { return strcmp(name, hook->name.chars()) == 0; } + static inline uint32_t hash(const detail::CharsAndLength &key) + { + return key.hash(); + } }; enum EventHookMode diff --git a/core/HalfLife2.h b/core/HalfLife2.h index 0525dda9..51212d4e 100644 --- a/core/HalfLife2.h +++ b/core/HalfLife2.h @@ -92,13 +92,21 @@ struct DataTableInfo { return strcmp(name, info.prop->GetName()) == 0; } + static inline uint32_t hash(const detail::CharsAndLength &key) + { + return key.hash(); + } }; static inline bool matches(const char *name, const DataTableInfo *info) { return strcmp(name, info->sc->GetName()) == 0; } - + static inline uint32_t hash(const detail::CharsAndLength &key) + { + return key.hash(); + } + DataTableInfo(ServerClass *sc) : sc(sc) { @@ -114,6 +122,10 @@ struct DataMapCachePolicy { return strcmp(name, info.prop->fieldName) == 0; } + static inline uint32_t hash(const detail::CharsAndLength &key) + { + return key.hash(); + } }; typedef NameHashSet DataMapCache; diff --git a/core/logic/AdminCache.h b/core/logic/AdminCache.h index 0cdd5859..18aa2361 100644 --- a/core/logic/AdminCache.h +++ b/core/logic/AdminCache.h @@ -82,6 +82,10 @@ struct AuthMethod { return strcmp(name, method->name.c_str()) == 0; } + static inline uint32_t hash(const detail::CharsAndLength &key) + { + return key.hash(); + } }; struct UserAuth diff --git a/core/logic/GameConfigs.h b/core/logic/GameConfigs.h index 3b40ea27..911443ca 100644 --- a/core/logic/GameConfigs.h +++ b/core/logic/GameConfigs.h @@ -72,6 +72,10 @@ public: //NameHashSet { return strcmp(key, value->m_File) == 0; } + static inline uint32_t hash(const detail::CharsAndLength &key) + { + return key.hash(); + } private: char m_File[PLATFORM_MAX_PATH]; char m_CurFile[PLATFORM_MAX_PATH]; diff --git a/core/logic/HandleSys.h b/core/logic/HandleSys.h index 6643c920..54e91751 100644 --- a/core/logic/HandleSys.h +++ b/core/logic/HandleSys.h @@ -111,6 +111,10 @@ struct QHandleType { return type->name && type->name->compare(key) == 0; } + static inline uint32_t hash(const detail::CharsAndLength &key) + { + return key.hash(); + } }; typedef ke::Lambda HandleReporter; diff --git a/core/logic/Native.h b/core/logic/Native.h index 8030513b..6c7ff188 100644 --- a/core/logic/Native.h +++ b/core/logic/Native.h @@ -37,6 +37,7 @@ #include #include #include +#include #include "common_logic.h" class CNativeOwner; @@ -94,6 +95,10 @@ struct Native : public ke::Refcounted { return strcmp(name, entry->name()) == 0; } + static inline uint32_t hash(const detail::CharsAndLength &key) + { + return key.hash(); + } }; diff --git a/core/logic/PluginSys.cpp b/core/logic/PluginSys.cpp index 389cf4d4..dbef1c12 100644 --- a/core/logic/PluginSys.cpp +++ b/core/logic/PluginSys.cpp @@ -31,7 +31,6 @@ #include #include -#include #include "PluginSys.h" #include "ShareSys.h" #include @@ -47,7 +46,6 @@ #include "frame_tasks.h" #include #include -#include #include #include @@ -934,38 +932,16 @@ void CPluginManager::LoadPluginsFromDir(const char *basedir, const char *localpa libsys->CloseDirectory(dir); } -#if defined PLATFORM_WINDOWS || defined PLATFORM_APPLE -char *strdup_tolower(const char *input) -{ - char *str = strdup(input); - - for (char *c = str; *c; c++) - { - *c = tolower((unsigned char)*c); - } - - return str; -} -#endif - LoadRes CPluginManager::LoadPlugin(CPlugin **aResult, const char *path, bool debug, PluginType type) { if (m_LoadingLocked) return LoadRes_NeverLoad; -/* For windows & mac, we convert the path to lower-case in order to avoid duplicate plugin loading */ -#if defined PLATFORM_WINDOWS || defined PLATFORM_APPLE - ke::UniquePtr finalPath = ke::UniquePtr(strdup_tolower(path)); -#else - ke::UniquePtr finalPath = ke::UniquePtr(strdup(path)); -#endif - - /** * Does this plugin already exist? */ CPlugin *pPlugin; - if (m_LoadLookup.retrieve(finalPath.get(), &pPlugin)) + if (m_LoadLookup.retrieve(path, &pPlugin)) { /* Check to see if we should try reloading it */ if (pPlugin->GetStatus() == Plugin_BadLoad @@ -978,12 +954,11 @@ LoadRes CPluginManager::LoadPlugin(CPlugin **aResult, const char *path, bool deb { if (aResult) *aResult = pPlugin; - return LoadRes_AlreadyLoaded; } } - CPlugin *plugin = CompileAndPrep(finalPath.get()); + CPlugin *plugin = CompileAndPrep(path); // Assign our outparam so we can return early. It must be set. *aResult = plugin; @@ -2416,4 +2391,4 @@ static OldPluginAPI sOldPluginAPI; IPluginManager *CPluginManager::GetOldAPI() { return &sOldPluginAPI; -} +} \ No newline at end of file diff --git a/core/logic/PluginSys.h b/core/logic/PluginSys.h index 43f04c7b..4a6b617b 100644 --- a/core/logic/PluginSys.h +++ b/core/logic/PluginSys.h @@ -143,11 +143,6 @@ public: */ static CPlugin *Create(const char *file); - static inline bool matches(const char *file, const CPlugin *plugin) - { - return strcmp(plugin->m_filename, file) == 0; - } - public: // Evicts the plugin from memory and sets an error state. void EvictWithError(PluginStatus status, const char *error_fmt, ...); @@ -483,7 +478,36 @@ private: typedef decltype(m_listeners)::iterator ListenerIter; typedef decltype(m_plugins)::iterator PluginIter; - NameHashSet m_LoadLookup; + struct CPluginPolicy + { + static inline uint32_t hash(const detail::CharsAndLength &key) + { +/* For windows & mac, we convert the path to lower-case in order to avoid duplicate plugin loading */ +#if defined PLATFORM_WINDOWS || defined PLATFORM_APPLE + ke::AString original(key.chars()); + ke::AString lower = original.lowercase(); + + return detail::CharsAndLength(lower.chars()).hash(); +#else + return key.hash(); +#endif + } + + static inline bool matches(const char *file, const CPlugin *plugin) + { + const char *pluginFileChars = const_cast(plugin)->GetFilename(); +#if defined PLATFORM_WINDOWS || defined PLATFORM_APPLE + ke::AString pluginFile = ke::AString(pluginFileChars).lowercase(); + ke::AString input = ke::AString(file).lowercase(); + + return pluginFile == input; +#else + return strcmp(pluginFileChars, file) == 0; +#endif + } + }; + NameHashSet m_LoadLookup; + bool m_AllPluginsLoaded; IdentityToken_t *m_MyIdent; diff --git a/core/logic/RootConsoleMenu.h b/core/logic/RootConsoleMenu.h index 4b687bec..c240a488 100644 --- a/core/logic/RootConsoleMenu.h +++ b/core/logic/RootConsoleMenu.h @@ -46,6 +46,10 @@ struct ConsoleEntry { return strcmp(name, entry->command.c_str()) == 0; } + static inline uint32_t hash(const detail::CharsAndLength &key) + { + return key.hash(); + } }; class RootConsoleMenu : diff --git a/core/logic/smn_maplists.cpp b/core/logic/smn_maplists.cpp index 093aaa15..2393a141 100644 --- a/core/logic/smn_maplists.cpp +++ b/core/logic/smn_maplists.cpp @@ -58,6 +58,10 @@ struct maplist_info_t { return strcmp(value->name, key) == 0; } + static inline uint32_t hash(const detail::CharsAndLength &key) + { + return key.hash(); + } }; #define MAPLIST_FLAG_MAPSFOLDER (1<<0) /**< On failure, use all maps in the maps folder. */ diff --git a/core/smn_console.cpp b/core/smn_console.cpp index 43f8ccc6..799e1359 100644 --- a/core/smn_console.cpp +++ b/core/smn_console.cpp @@ -184,6 +184,10 @@ private: { return strcmp(name, base->GetName()) == 0; } + static inline uint32_t hash(const detail::CharsAndLength &key) + { + return key.hash(); + } }; NameHashSet m_CmdFlags; } s_CommandFlagsHelper; diff --git a/extensions/clientprefs/cookie.h b/extensions/clientprefs/cookie.h index 9684b264..31b59f35 100644 --- a/extensions/clientprefs/cookie.h +++ b/extensions/clientprefs/cookie.h @@ -96,6 +96,10 @@ struct Cookie { return strcmp(name, cookie->name) == 0; } + static inline uint32_t hash(const detail::CharsAndLength &key) + { + return key.hash(); + } }; class CookieManager : public IClientListener, public IPluginsListener diff --git a/extensions/topmenus/TopMenu.h b/extensions/topmenus/TopMenu.h index a22a1ba0..298c7f58 100644 --- a/extensions/topmenus/TopMenu.h +++ b/extensions/topmenus/TopMenu.h @@ -77,6 +77,10 @@ struct topmenu_object_t { return strcmp(name, topmenu->name) == 0; } + static inline uint32_t hash(const detail::CharsAndLength &key) + { + return key.hash(); + } }; struct topmenu_category_t diff --git a/public/sm_namehashset.h b/public/sm_namehashset.h index 5e6fbe95..26507353 100644 --- a/public/sm_namehashset.h +++ b/public/sm_namehashset.h @@ -48,10 +48,12 @@ namespace SourceMod { -// The HashPolicy type must have this method: +// The HashPolicy type must have these methods: // static bool matches(const char *key, const T &value); +// static uint32_t hash(const CharsAndLength &key); // -// Depending on what lookup types are used. +// Depending on what lookup types are used, and how hashing should be done. +// Most of the time, key hashing will just call the key's hash() method. // // 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 @@ -69,7 +71,7 @@ class NameHashSet : public ke::SystemAllocatorPolicy static uint32_t hash(const CharsAndLength &key) { - return key.hash(); + return KeyPolicyType::hash(key); } static bool matches(const CharsAndLength &key, const KeyType &value) @@ -85,9 +87,9 @@ class NameHashSet : public ke::SystemAllocatorPolicy { typedef KeyType *Payload; - static uint32_t hash(const detail::CharsAndLength &key) + static uint32_t hash(const CharsAndLength &key) { - return key.hash(); + return KeyType::hash(key); } static bool matches(const CharsAndLength &key, const KeyType *value)