Cvars: Rearrange a bit some code

Changed class CCVar -> struct CvarInfo
Added CvarManager class and moved some code there
Code of registering a cvar is rewritten
Cvars datas are stored in a hashtable for fast lookup
For natives compatibility, an inline list is kept (though CList -> ke::InlineList)
Replace some CVAR_GET/SEt_ by FindVar
This commit is contained in:
Arkshine 2015-01-19 19:17:41 +01:00
parent f973f5beb7
commit cdc7d550eb
8 changed files with 511 additions and 154 deletions

View File

@ -1923,11 +1923,15 @@ static cell AMX_NATIVE_CALL get_pcvar_string(AMX *amx, cell *params)
static cell AMX_NATIVE_CALL get_cvar_string(AMX *amx, cell *params) /* 3 param */
{
int ilen;
char* sptemp = get_amxstring(amx, params[1], 0, ilen);
int length;
const char* name = get_amxstring(amx, params[1], 0, length);
const char *value = CVAR_GET_STRING(sptemp);
return set_amxstring_utf8(amx, params[2], value, strlen(value), params[3] + 1); // + EOS
cvar_t* var = g_CvarManager.FindCvar(name);
const char *value = var ? var->string : "";
length = var ? strlen(value) : 0;
return set_amxstring_utf8(amx, params[2], value, length, params[3] + 1); // + EOS
}
static cell AMX_NATIVE_CALL get_pcvar_float(AMX *amx, cell *params)
@ -1939,18 +1943,17 @@ static cell AMX_NATIVE_CALL get_pcvar_float(AMX *amx, cell *params)
return 0;
}
REAL val = (REAL)ptr->value;
return amx_ftoc(val);
return amx_ftoc(ptr->value);
}
static cell AMX_NATIVE_CALL get_cvar_float(AMX *amx, cell *params) /* 1 param */
{
int ilen;
int length;
const char* name = get_amxstring(amx, params[1], 0, length);
REAL pFloat = CVAR_GET_FLOAT(get_amxstring(amx, params[1], 0, ilen));
cvar_t* var = g_CvarManager.FindCvar(name);
return amx_ftoc(pFloat);
return var ? amx_ftoc(var->value) : 0;
}
static cell AMX_NATIVE_CALL set_pcvar_float(AMX *amx, cell *params)
@ -1962,15 +1965,24 @@ static cell AMX_NATIVE_CALL set_pcvar_float(AMX *amx, cell *params)
return 0;
}
UTIL_Format(CVarTempBuffer,sizeof(CVarTempBuffer)-1,"%f",amx_ctof(params[2]));
(*g_engfuncs.pfnCvar_DirectSet)(ptr, &CVarTempBuffer[0]);
UTIL_Format(CVarTempBuffer, sizeof(CVarTempBuffer) - 1, "%f", amx_ctof(params[2]));
CVAR_DIRECTSET(ptr, &CVarTempBuffer[0]);
return 1;
}
static cell AMX_NATIVE_CALL set_cvar_float(AMX *amx, cell *params) /* 2 param */
{
int ilen;
CVAR_SET_FLOAT(get_amxstring(amx, params[1], 0, ilen), amx_ctof(params[2]));
int length;
const char* name = get_amxstring(amx, params[1], 0, length);
cvar_t* var = g_CvarManager.FindCvar(name);
if (var)
{
UTIL_Format(CVarTempBuffer, sizeof(CVarTempBuffer) - 1, "%f", amx_ctof(params[2]));
CVAR_DIRECTSET(var, &CVarTempBuffer[0]);
}
return 1;
}
@ -1989,8 +2001,13 @@ static cell AMX_NATIVE_CALL get_pcvar_num(AMX *amx, cell *params)
static cell AMX_NATIVE_CALL get_cvar_num(AMX *amx, cell *params) /* 1 param */
{
int ilen;
return (int)CVAR_GET_FLOAT(get_amxstring(amx, params[1], 0, ilen));
int length;
const char* name = get_amxstring(amx, params[1], 0, length);
cvar_t* var = g_CvarManager.FindCvar(name);
return var ? (int)var->value : 0;
}
static cell AMX_NATIVE_CALL set_pcvar_num(AMX *amx, cell *params)
@ -2003,26 +2020,39 @@ static cell AMX_NATIVE_CALL set_pcvar_num(AMX *amx, cell *params)
}
UTIL_Format(CVarTempBuffer,sizeof(CVarTempBuffer)-1,"%d",params[2]);
(*g_engfuncs.pfnCvar_DirectSet)(ptr, &CVarTempBuffer[0]);
CVAR_DIRECTSET(ptr, &CVarTempBuffer[0]);
return 1;
}
static cell AMX_NATIVE_CALL set_cvar_num(AMX *amx, cell *params) /* 2 param */
{
int ilen;
CVAR_SET_FLOAT(get_amxstring(amx, params[1], 0, ilen), (float)params[2]);
int length;
const char* name = get_amxstring(amx, params[1], 0, length);
int value = params[2];
cvar_t* var = g_CvarManager.FindCvar(name);
if (var)
{
UTIL_Format(CVarTempBuffer, sizeof(CVarTempBuffer) - 1, "%d", value);
CVAR_DIRECTSET(var, &CVarTempBuffer[0]);
}
return 1;
}
static cell AMX_NATIVE_CALL set_cvar_string(AMX *amx, cell *params) /* 2 param */
{
int ilen;
char* sptemp = get_amxstring(amx, params[1], 0, ilen);
char* szValue = get_amxstring(amx, params[2], 1, ilen);
int length;
const char* name = get_amxstring(amx, params[1], 0, length);
CVAR_SET_STRING(sptemp, szValue);
cvar_t* var = g_CvarManager.FindCvar(name);
if (var)
{
CVAR_DIRECTSET(var, get_amxstring(amx, params[2], 1, length));
}
return 1;
}
@ -2038,7 +2068,7 @@ static cell AMX_NATIVE_CALL set_pcvar_string(AMX *amx, cell *params) /* 2 param
int len;
(*g_engfuncs.pfnCvar_DirectSet)(ptr, get_amxstring(amx,params[2],0,len));
CVAR_DIRECTSET(ptr, get_amxstring(amx,params[2],0,len));
return 1;
}
@ -2598,40 +2628,28 @@ static cell AMX_NATIVE_CALL task_exists(AMX *amx, cell *params) /* 1 param */
static cell AMX_NATIVE_CALL cvar_exists(AMX *amx, cell *params) /* 1 param */
{
int ilen;
return (CVAR_GET_POINTER(get_amxstring(amx, params[1], 0, ilen)) ? 1 : 0);
return (g_CvarManager.FindCvar(get_amxstring(amx, params[1], 0, ilen)) ? 1 : 0);
}
static cell AMX_NATIVE_CALL register_cvar(AMX *amx, cell *params) /* 3 param */
{
int i;
char* temp = get_amxstring(amx, params[1], 0, i);
int length;
const char* name = get_amxstring(amx, params[1], 0, length);
const char* value = get_amxstring(amx, params[2], 1, length);
int flags = params[3];
float fvalue = amx_ctof(params[4]);
CPluginMngr::CPlugin *plugin = g_plugins.findPluginFast(amx);
if (CheckBadConList(temp, 0))
if (CheckBadConList(name, 0))
{
plugin->AddToFailCounter(1);
}
if (!g_cvars.find(temp))
{
CCVar* cvar = new CCVar(temp, plugin->getName(), params[3], amx_ctof(params[4]));
cvar_t* var = g_CvarManager.CreateCvar(name, value, fvalue, flags, plugin->getName(), plugin->getId());
cvar->plugin_id = plugin->getId();
g_cvars.put(cvar);
if (CVAR_GET_POINTER(temp) == 0)
{
static cvar_t cvar_reg_helper;
cvar_reg_helper = *(cvar->getCvar());
CVAR_REGISTER(&cvar_reg_helper);
}
CVAR_SET_STRING(temp, get_amxstring(amx, params[2], 1, i));
return reinterpret_cast<cell>(CVAR_GET_POINTER(temp));
}
return reinterpret_cast<cell>(CVAR_GET_POINTER(temp));
return reinterpret_cast<cell>(var);
}
static cell AMX_NATIVE_CALL get_user_ping(AMX *amx, cell *params) /* 3 param */
@ -3022,30 +3040,17 @@ static cell AMX_NATIVE_CALL remove_quotes(AMX *amx, cell *params) /* 1 param */
//native get_plugins_cvar(id, name[], namelen, &flags=0, &plugin_id=0, &pcvar_handle=0);
static cell AMX_NATIVE_CALL get_plugins_cvar(AMX *amx, cell *params)
{
int id = params[1];
int iter_id = 0;
CvarInfo* info = g_CvarManager.FindCvar(params[1]);
for (CList<CCVar>::iterator iter=g_cvars.begin(); iter; ++iter)
if (info)
{
if (id == iter_id)
{
CCVar *var = &(*iter);
set_amxstring(amx, params[2], var->getName(), params[3]);
cvar_t *ptr = CVAR_GET_POINTER(var->getName());
if (!ptr)
{
return 0;
}
cell *addr = get_amxaddr(amx, params[4]);
*addr = ptr->flags;
addr = get_amxaddr(amx, params[5]);
*addr = var->plugin_id;
addr = get_amxaddr(amx, params[6]);
*addr = (cell)ptr;
set_amxstring(amx, params[2], info->name.chars(), params[3]);
*get_amxaddr(amx, params[4]) = info->var->flags;
*get_amxaddr(amx, params[5]) = info->pluginId;
*get_amxaddr(amx, params[6]) = reinterpret_cast<cell>(info->var);
return 1;
}
iter_id++;
}
return 0;
}
@ -3053,7 +3058,7 @@ static cell AMX_NATIVE_CALL get_plugins_cvar(AMX *amx, cell *params)
//native get_plugins_cvarsnum();
static cell AMX_NATIVE_CALL get_plugins_cvarsnum(AMX *amx, cell *params)
{
return g_cvars.size();
return g_CvarManager.GetRegCvarsCount();
}
static cell AMX_NATIVE_CALL get_user_aiming(AMX *amx, cell *params) /* 4 param */
@ -3107,7 +3112,7 @@ static cell AMX_NATIVE_CALL remove_cvar_flags(AMX *amx, cell *params)
if (!strcmp(sCvar, "amx_version") || !strcmp(sCvar, "amxmodx_version") || !strcmp(sCvar, "fun_version") || !strcmp(sCvar, "sv_cheats"))
return 0;
cvar_t* pCvar = CVAR_GET_POINTER(sCvar);
cvar_t* pCvar = g_CvarManager.FindCvar(sCvar);
if (pCvar)
{
@ -3135,7 +3140,7 @@ static cell AMX_NATIVE_CALL get_cvar_flags(AMX *amx, cell *params)
int ilen;
char* sCvar = get_amxstring(amx, params[1], 0, ilen);
cvar_t* pCvar = CVAR_GET_POINTER(sCvar);
cvar_t* pCvar = g_CvarManager.FindCvar(sCvar);
return pCvar ? pCvar->flags : 0;
}
@ -3162,7 +3167,7 @@ static cell AMX_NATIVE_CALL set_cvar_flags(AMX *amx, cell *params)
if (!strcmp(sCvar, "amx_version") || !strcmp(sCvar, "amxmodx_version") || !strcmp(sCvar, "fun_version") || !strcmp(sCvar, "sv_cheats"))
return 0;
cvar_t* pCvar = CVAR_GET_POINTER(sCvar);
cvar_t* pCvar = g_CvarManager.FindCvar(sCvar);
if (pCvar)
{
@ -4448,9 +4453,9 @@ static cell AMX_NATIVE_CALL DestroyForward(AMX *amx, cell *params)
static cell AMX_NATIVE_CALL get_cvar_pointer(AMX *amx, cell *params)
{
int len;
char *temp = get_amxstring(amx, params[1], 0, len);
char *name = get_amxstring(amx, params[1], 0, len);
cvar_t *ptr = CVAR_GET_POINTER(temp);
cvar_t *ptr = g_CvarManager.FindCvar(name);
return reinterpret_cast<cell>(ptr);
}

View File

@ -162,7 +162,6 @@ extern CTaskMngr g_tasksMngr;
extern CPlayer g_players[33];
extern CPlayer* mPlayer;
extern CmdMngr g_commands;
extern CList<CCVar> g_cvars;
extern CList<ForceObject> g_forcemodels;
extern CList<ForceObject> g_forcesounds;
extern CList<ForceObject> g_forcegeneric;

View File

@ -11,25 +11,52 @@
#include "amxmodx.h"
#include <CDetour/detours.h>
CDetour *Cvar_DirectSetDetour;
CvarManager g_CvarManager;
DETOUR_DECL_STATIC2(Cvar_DirectSet, void, struct cvar_s*, var, const char*, value)
{
if (var && value)
static bool calledFromCallback = false;
if (!calledFromCallback && var && value)
{
if (strcmp(var->string, value) != 0)
{
calledFromCallback = true;
if (executeForwards(FF_CvarChanged, reinterpret_cast<cell>(var), var->string, value, var->name) > 0)
{
return;
//return;
}
calledFromCallback = false;
}
}
DETOUR_STATIC_CALL(Cvar_DirectSet)(var, value);
}
void CreateCvarHook(void)
CvarManager::CvarManager() : m_AmxmodxCvars(0), m_HookDetour(nullptr)
{
}
CvarManager::~CvarManager()
{
CvarsList::iterator iter = m_Cvars.begin();
while (iter != m_Cvars.end())
{
CvarInfo* info = (*iter);
iter = m_Cvars.erase(iter);
delete info;
}
m_Cache.clear();
m_HookDetour->Destroy();
}
void CvarManager::CreateCvarHook(void)
{
// void PF_Cvar_DirectSet(struct cvar_s *var, const char *value) // = pfnCvar_DirectSet
// {
@ -69,11 +96,160 @@ void CreateCvarHook(void)
if (functionAddress)
{
CDetour *Cvar_DirectSetDetour = DETOUR_CREATE_STATIC_FIXED(Cvar_DirectSet, (void *)functionAddress);
m_HookDetour = DETOUR_CREATE_STATIC_FIXED(Cvar_DirectSet, (void *)functionAddress);
if (Cvar_DirectSetDetour)
if (m_HookDetour)
{
Cvar_DirectSetDetour->EnableDetour();
m_HookDetour->EnableDetour();
}
}
}
cvar_t* CvarManager::CreateCvar(const char* name, const char* value, float fvalue, int flags, const char* plugin, int plugnId)
{
cvar_t* var = nullptr;
CvarInfo* info = nullptr;
// Is cvar already cached ?
if (!m_Cache.retrieve(name, &info))
{
// Not cached - Is cvar already exist?
var = CVAR_GET_POINTER(name);
// Whether it exists, we need to prepare a new entry.
info = new CvarInfo();
// Shared datas.
info->name = name;
info->plugin = plugin;
info->pluginId = plugnId;
if (var)
{
// Cvar already exists. Just copy.
// "string" will be set after. "value" and "next" are automatically set.
info->var = var;
info->defaultval = var->string;
info->amxmodx = false;
}
else
{
// Registers a new cvar.
static cvar_t cvar_reg_helper;
// "string" will be set after. "value" and "next" are automatically set.
cvar_reg_helper.name = info->name.chars();
cvar_reg_helper.string = "";
cvar_reg_helper.flags = flags;
// Adds cvar to global list.
CVAR_REGISTER(&cvar_reg_helper);
// Registering can fail if name is already a registered command.
var = CVAR_GET_POINTER(name);
// If so, we can't go further.
if (!var)
{
delete info;
return nullptr;
}
// If ok, we got a valid pointer, we can copy.
info->var = var;
info->defaultval = value;
info->amxmodx = true;
// Keeps track count of cvars registered by AMXX.
++m_AmxmodxCvars;
}
// Add a new entry in the caches.
m_Cvars.append(info);
m_Cache.insert(name, info);
// Make sure that whether an existing or new cvar is set to the given value.
CVAR_DIRECTSET(var, value);
}
return info->var;
}
cvar_t* CvarManager::FindCvar(const char* name)
{
cvar_t* var = nullptr;
CvarInfo* info = nullptr;
// Do we have already cvar in cache?
if (m_Cache.retrieve(name, &info))
{
return info->var;
}
// Cvar doesn't exist.
if (!(var = CVAR_GET_POINTER(name)))
{
return nullptr;
}
// Create a new entry.
info = new CvarInfo();
info->var = var;
info->name = name;
info->plugin = "";
info->pluginId = -1;
info->amxmodx = false;
// Add entry in the caches.
m_Cvars.append(info);
m_Cache.insert(name, info);
return var;
}
CvarInfo* CvarManager::FindCvar(size_t index)
{
// Used by get_plugins_cvar native.
// For compatibility, only cvars registered by AMXX are concerned.
size_t iter_id = 0;
for (CvarsList::iterator iter = m_Cvars.begin(); iter != m_Cvars.end(); iter++)
{
if (iter->amxmodx && iter_id++ == index)
{
return *(iter);
}
}
return nullptr;
}
size_t CvarManager::GetRegCvarsCount()
{
return m_AmxmodxCvars;
}
void CvarManager::OnConsoleCommand()
{
print_srvconsole("Registered cvars:\n");
print_srvconsole(" %-24.23s %-24.23s %-16.15s\n", "name", "value", "plugin");
size_t index = 0;
ke::AString pluginName;
if (CMD_ARGC() > 2) // Searching for cvars registered to a plugin
{
pluginName = CMD_ARGV(2);
}
for (CvarsList::iterator iter = m_Cvars.begin(); iter != m_Cvars.end(); iter++)
{
CvarInfo* ci = (*iter);
if (ci->amxmodx && (!pluginName.length() || strncmp(ci->name.chars(), pluginName.chars(), pluginName.length()) == 0))
{
print_srvconsole(" [%3d] %-24.23s %-24.23s %-16.15s\n", ++index, ci->name.chars(), ci->var->string, ci->plugin.chars());
}
}
}

View File

@ -11,50 +11,53 @@
#define CVARS_H
#include "cvardef.h"
#include <am-string.h>
#include <am-inlinelist.h>
#include <sm_namehashset.h>
class CDetour;
class CCVar
struct CvarInfo : public ke::InlineListNode<CvarInfo>
{
cvar_t cvar;
cvar_t* var;
ke::AString name;
ke::AString defaultval;
ke::AString plugin;
int pluginId;
bool amxmodx;
public:
CCVar(const char* pname, const char* pplugin, int pflags, float pvalue) : name(pname), plugin(pplugin)
static inline bool matches(const char *name, const CvarInfo* info)
{
cvar.name = name.chars();
cvar.flags = pflags;
cvar.string = "";
cvar.value = pvalue;
return strcmp(name, info->var->name) == 0;
}
inline cvar_t* getCvar()
{
return &cvar;
}
inline const char* getPluginName()
{
return plugin.chars();
}
inline const char* getName()
{
return name.chars();
}
inline bool operator == (const char* string)
{
return name.compare(string) == 0;
}
int plugin_id;
};
void CreateCvarHook(void);
typedef NameHashSet<CvarInfo*> CvarsCache;
typedef ke::InlineList<CvarInfo> CvarsList;
extern CDetour *Cvar_DirectSetDetour;
class CvarManager
{
public:
CvarManager();
~CvarManager();
public:
void CreateCvarHook();
cvar_t* CreateCvar(const char* name, const char* value, float fvalue, int flags, const char* plugin, int plugnId);
cvar_t* FindCvar(const char* name);
CvarInfo* FindCvar(size_t index);
size_t GetRegCvarsCount();
void OnConsoleCommand();
private:
CvarsCache m_Cache;
CvarsList m_Cvars;
size_t m_AmxmodxCvars;
CDetour* m_HookDetour;
};
extern CvarManager g_CvarManager;
#endif // CVARS_H

View File

@ -64,7 +64,6 @@ extern CVector<CAdminData *> DynamicAdmins;
CLog g_log;
CForwardMngr g_forwards;
CList<CPlayer*> g_auth;
CList<CCVar> g_cvars;
CList<ForceObject> g_forcemodels;
CList<ForceObject> g_forcesounds;
CList<ForceObject> g_forcegeneric;
@ -122,7 +121,7 @@ cvar_t init_amxmodx_modules = {"amxmodx_modules", "", FCVAR_SPONLY};
cvar_t init_amxmodx_debug = {"amx_debug", "1", FCVAR_SPONLY};
cvar_t init_amxmodx_mldebug = {"amx_mldebug", "", FCVAR_SPONLY};
cvar_t init_amxmodx_language = {"amx_language", "en", FCVAR_SERVER};
cvar_t init_amxmodx_cl_langs = {"amx_client_languages", "", FCVAR_SERVER};
cvar_t init_amxmodx_cl_langs = {"amx_client_languages", "1", FCVAR_SERVER};
cvar_t* amxmodx_version = NULL;
cvar_t* amxmodx_modules = NULL;
cvar_t* amxmodx_language = NULL;
@ -1492,7 +1491,7 @@ C_DLLEXPORT int Meta_Attach(PLUG_LOADTIME now, META_FUNCTIONS *pFunctionTable, m
FlagMan.SetFile("cmdaccess.ini");
CreateCvarHook();
g_CvarManager.CreateCvarHook();
return (TRUE);
}
@ -1522,7 +1521,6 @@ C_DLLEXPORT int Meta_Detach(PLUG_LOADTIME now, PL_UNLOAD_REASON reason)
g_vault.clear();
g_xvars.clear();
g_plugins.clear();
g_cvars.clear();
g_langMngr.Clear();
ClearMessages();

View File

@ -111,32 +111,7 @@ void amx_command()
}
else if (!strcmp(cmd, "cvars"))
{
print_srvconsole("Registered cvars:\n");
print_srvconsole(" %-24.23s %-24.23s %-16.15s\n", "name", "value", "plugin");
int ammount = 0;
if (CMD_ARGC() > 2) // Searching for cvars registered to a plugin
{
const char* targetname = CMD_ARGV(2);
size_t len = strlen(targetname);
for (CList<CCVar>::iterator a = g_cvars.begin(); a; ++a)
{
if (strncmp((*a).getPluginName(), targetname, len) == 0)
{
print_srvconsole(" [%3d] %-24.23s %-24.23s %-16.15s\n", ++ammount, (*a).getName(), CVAR_GET_STRING((*a).getName()), (*a).getPluginName());
}
}
}
else // No search
{
for (CList<CCVar>::iterator a = g_cvars.begin(); a; ++a)
{
print_srvconsole(" [%3d] %-24.23s %-24.23s %-16.15s\n", ++ammount, (*a).getName(), CVAR_GET_STRING((*a).getName()), (*a).getPluginName());
}
}
print_srvconsole("%d cvars\n", ammount);
g_CvarManager.OnConsoleCommand();
}
else if (!strcmp(cmd, "cmds"))
{

View File

@ -29,8 +29,8 @@ public plugin_init()
register_dictionary("common.txt")
register_dictionary("languages.txt")
g_cvarClientLanguages = register_cvar("amx_client_languages", "1")
g_cvarDisplayClientMessage = register_cvar("amx_language_display_msg", "1")
g_cvarClientLanguages = get_cvar_pointer("amx_client_languages")
g_cvarServerLanguage = get_cvar_pointer("amx_language");
register_clcmd("amx_langmenu", "cmdLangMenu", ADMIN_ALL)

201
public/sm_namehashset.h Normal file
View File

@ -0,0 +1,201 @@
/**
* 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 <http://www.gnu.org/licenses/>.
*
* 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 <http://www.sourcemod.net/license.php>.
*
* 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 <am-allocator-policies.h>
#include <am-hashmap.h>
#include <am-string.h>
#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 <typename T, typename KeyPolicy = T>
class NameHashSet : public ke::SystemAllocatorPolicy
{
typedef detail::CharsAndLength CharsAndLength;
// Default policy type: the two types are different. Use them directly.
template <typename KeyType, typename KeyPolicyType>
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 <typename KeyType>
struct Policy<KeyType *, KeyType *>
{
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 ke::HashTable<Policy<T, KeyPolicy>, ke::SystemAllocatorPolicy> Internal;
public:
NameHashSet()
{
if (!table_.init())
this->reportOutOfMemory();
}
typedef typename Internal::Result Result;
typedef typename Internal::Insert Insert;
typedef typename Internal::iterator iterator;
Result find(const char *aKey)
{
return table_.find(aKey);
}
Insert findForAdd(const char *aKey)
{
return table_.findForAdd(aKey);
}
void add(Insert &i, const T &value)
{
return table_.add(i, value);
}
void add(Insert &i, T &&value)
{
return table_.add(i, value);
}
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 insert(const char *aKey, T &&value)
{
CharsAndLength key(aKey);
Insert i = table_.findForAdd(key);
if (i.found())
return false;
return table_.add(i, value);
}
bool contains(const char *aKey)
{
CharsAndLength key(aKey);
Result r = table_.find(aKey);
return r.found();
}
bool remove(const char *aKey)
{
CharsAndLength key(aKey);
Result r = table_.find(key);
if (!r.found())
return false;
table_.remove(r);
return true;
}
void remove(Result &r)
{
table_.remove(r);
}
void clear()
{
table_.clear();
}
size_t mem_usage() const
{
return table_.estimateMemoryUse();
}
iterator iter()
{
return iterator(&table_);
}
private:
Internal table_;
};
//}
#endif // _include_sourcemod_namehashset_h_