mirror of
https://github.com/alliedmodders/sourcemod.git
synced 2025-12-06 18:08:36 +00:00
Add IntMap methodmap (#2018)
* Add new IntHashMap and IntMap natives This is a continuation of #579. [HashMap] Adds new IntHashMap and IntMap natives. This patch makes the following changes * Refactors StringHashMap to a generic HashMap template * Adds the IntHashMap class * Adds new IntMap natives * Adds IntMap tests to the tries test suite [HashMap] Reverted rename of CharsAndLength [HashMap] Use more descriptive template names [HashMap] Removed old-style natives [HashMap] Removed IntHash class [HashMap] Reverted some search & replace errors Co-authored-by: Geoffrey McRae <geoff@hostfission.com> * Fix spelling mistake + include * Fix tries test * Update tests with clone + ContainsKey --------- Co-authored-by: Geoffrey McRae <geoff@hostfission.com> Co-authored-by: Nicholas Hastings <nshastings@gmail.com>
This commit is contained in:
parent
6c3486d732
commit
34e9605519
@ -38,7 +38,7 @@
|
||||
#include <am-inlinelist.h>
|
||||
#include <am-refcounting.h>
|
||||
#include <am-utility.h>
|
||||
#include <sm_stringhashmap.h>
|
||||
#include <sm_hashmap.h>
|
||||
|
||||
#include "sm_globals.h"
|
||||
#include "sourcemm_api.h"
|
||||
|
||||
@ -43,7 +43,7 @@
|
||||
#include <compat_wrappers.h>
|
||||
#include "concmd_cleaner.h"
|
||||
#include "PlayerManager.h"
|
||||
#include <sm_stringhashmap.h>
|
||||
#include <sm_hashmap.h>
|
||||
|
||||
using namespace SourceHook;
|
||||
|
||||
|
||||
@ -34,7 +34,7 @@
|
||||
#include "sm_globals.h"
|
||||
#include "sourcemm_api.h"
|
||||
#include <IForwardSys.h>
|
||||
#include <sm_stringhashmap.h>
|
||||
#include <sm_hashmap.h>
|
||||
|
||||
namespace SourceMod {
|
||||
class ICommandArgs;
|
||||
|
||||
@ -36,7 +36,7 @@
|
||||
#include <ITextParsers.h>
|
||||
#include <IRootConsoleMenu.h>
|
||||
#include <am-string.h>
|
||||
#include <sm_stringhashmap.h>
|
||||
#include <sm_hashmap.h>
|
||||
|
||||
using namespace SourceMod;
|
||||
|
||||
|
||||
@ -38,7 +38,7 @@
|
||||
#include <am-utility.h>
|
||||
#include <am-hashset.h>
|
||||
#include <am-hashmap.h>
|
||||
#include <sm_stringhashmap.h>
|
||||
#include <sm_hashmap.h>
|
||||
#include <sm_namehashset.h>
|
||||
#include "sm_globals.h"
|
||||
#include "sm_queue.h"
|
||||
|
||||
@ -34,7 +34,7 @@
|
||||
|
||||
#include <IUserMessages.h>
|
||||
#include "sourcemm_api.h"
|
||||
#include <sm_stringhashmap.h>
|
||||
#include <sm_hashmap.h>
|
||||
#include "sm_stringutil.h"
|
||||
#include "CellRecipientFilter.h"
|
||||
#include "sm_globals.h"
|
||||
|
||||
@ -34,7 +34,7 @@
|
||||
|
||||
#include <IADTFactory.h>
|
||||
#include "common_logic.h"
|
||||
#include <sm_stringhashmap.h>
|
||||
#include <sm_hashmap.h>
|
||||
|
||||
using namespace SourceMod;
|
||||
|
||||
|
||||
@ -39,7 +39,7 @@
|
||||
#include <sh_list.h>
|
||||
#include <sh_string.h>
|
||||
#include <IForwardSys.h>
|
||||
#include <sm_stringhashmap.h>
|
||||
#include <sm_hashmap.h>
|
||||
#include <sm_namehashset.h>
|
||||
|
||||
using namespace SourceHook;
|
||||
|
||||
@ -36,7 +36,7 @@
|
||||
#include <IGameConfigs.h>
|
||||
#include <ITextParsers.h>
|
||||
#include <am-refcounting.h>
|
||||
#include <sm_stringhashmap.h>
|
||||
#include <sm_hashmap.h>
|
||||
#include <sm_namehashset.h>
|
||||
#include <unordered_set>
|
||||
|
||||
|
||||
@ -36,7 +36,7 @@
|
||||
#include <am-string.h>
|
||||
#include <am-utility.h>
|
||||
#include <am-refcounting.h>
|
||||
#include <sm_stringhashmap.h>
|
||||
#include <sm_hashmap.h>
|
||||
#include "common_logic.h"
|
||||
|
||||
class CNativeOwner;
|
||||
|
||||
@ -47,7 +47,7 @@
|
||||
#include <sh_string.h>
|
||||
#include "common_logic.h"
|
||||
#include <IRootConsoleMenu.h>
|
||||
#include <sm_stringhashmap.h>
|
||||
#include <sm_hashmap.h>
|
||||
#include <sm_namehashset.h>
|
||||
#include "ITranslator.h"
|
||||
#include "IGameConfigs.h"
|
||||
|
||||
@ -38,7 +38,7 @@
|
||||
#include <am-utility.h>
|
||||
#include <am-refcounting.h>
|
||||
#include <sh_list.h>
|
||||
#include <sm_stringhashmap.h>
|
||||
#include <sm_hashmap.h>
|
||||
#include <sm_namehashset.h>
|
||||
#include "common_logic.h"
|
||||
#include "Native.h"
|
||||
|
||||
@ -33,7 +33,7 @@
|
||||
#define _INCLUDE_SOURCEMOD_TRANSLATOR_H_
|
||||
|
||||
#include "common_logic.h"
|
||||
#include <sm_stringhashmap.h>
|
||||
#include <sm_hashmap.h>
|
||||
#include <sh_string.h>
|
||||
#include <sh_vector.h>
|
||||
#include "sm_memtable.h"
|
||||
|
||||
@ -35,12 +35,14 @@
|
||||
|
||||
#include "common_logic.h"
|
||||
#include <am-refcounting.h>
|
||||
#include <sm_stringhashmap.h>
|
||||
#include <sm_hashmap.h>
|
||||
#include "sm_memtable.h"
|
||||
#include <IHandleSys.h>
|
||||
|
||||
HandleType_t htCellTrie;
|
||||
HandleType_t htSnapshot;
|
||||
HandleType_t htIntCellTrie;
|
||||
HandleType_t htIntSnapshot;
|
||||
|
||||
enum EntryType
|
||||
{
|
||||
@ -171,6 +173,11 @@ struct CellTrie
|
||||
StringHashMap<Entry> map;
|
||||
};
|
||||
|
||||
struct IntCellTrie
|
||||
{
|
||||
IntHashMap<Entry> map;
|
||||
};
|
||||
|
||||
struct TrieSnapshot
|
||||
{
|
||||
TrieSnapshot()
|
||||
@ -187,6 +194,19 @@ struct TrieSnapshot
|
||||
BaseStringTable strings;
|
||||
};
|
||||
|
||||
struct IntTrieSnapshot
|
||||
{
|
||||
IntTrieSnapshot() {}
|
||||
|
||||
size_t mem_usage()
|
||||
{
|
||||
return length * sizeof(int);
|
||||
}
|
||||
|
||||
size_t length;
|
||||
std::unique_ptr<int[]> keys;
|
||||
};
|
||||
|
||||
class TrieHelpers :
|
||||
public SMGlobalClass,
|
||||
public IHandleTypeDispatch
|
||||
@ -196,11 +216,15 @@ public: //SMGlobalClass
|
||||
{
|
||||
htCellTrie = handlesys->CreateType("Trie", this, 0, NULL, NULL, g_pCoreIdent, NULL);
|
||||
htSnapshot = handlesys->CreateType("TrieSnapshot", this, 0, NULL, NULL, g_pCoreIdent, NULL);
|
||||
htIntCellTrie = handlesys->CreateType("IntTrie", this, 0, NULL, NULL, g_pCoreIdent, NULL);
|
||||
htIntSnapshot = handlesys->CreateType("IntTrieSnapshot", this, 0, NULL, NULL, g_pCoreIdent, NULL);
|
||||
}
|
||||
void OnSourceModShutdown()
|
||||
{
|
||||
handlesys->RemoveType(htSnapshot, g_pCoreIdent);
|
||||
handlesys->RemoveType(htCellTrie, g_pCoreIdent);
|
||||
handlesys->RemoveType(htIntSnapshot, g_pCoreIdent);
|
||||
handlesys->RemoveType(htIntCellTrie, g_pCoreIdent);
|
||||
}
|
||||
public: //IHandleTypeDispatch
|
||||
void OnHandleDestroy(HandleType_t type, void *object)
|
||||
@ -208,10 +232,21 @@ public: //IHandleTypeDispatch
|
||||
if (type == htCellTrie)
|
||||
{
|
||||
delete (CellTrie *)object;
|
||||
} else {
|
||||
}
|
||||
else if (type == htSnapshot)
|
||||
{
|
||||
TrieSnapshot *snapshot = (TrieSnapshot *)object;
|
||||
delete snapshot;
|
||||
}
|
||||
else if (type == htIntCellTrie)
|
||||
{
|
||||
delete (IntCellTrie *)object;
|
||||
}
|
||||
else if (type == htIntSnapshot)
|
||||
{
|
||||
IntTrieSnapshot *snapshot = (IntTrieSnapshot *)object;
|
||||
delete snapshot;
|
||||
}
|
||||
}
|
||||
bool GetHandleApproxSize(HandleType_t type, void *object, unsigned int *pSize)
|
||||
{
|
||||
@ -219,11 +254,28 @@ public: //IHandleTypeDispatch
|
||||
{
|
||||
CellTrie *pArray = (CellTrie *)object;
|
||||
*pSize = sizeof(CellTrie) + pArray->map.mem_usage();
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
else if (type == htSnapshot)
|
||||
{
|
||||
TrieSnapshot *snapshot = (TrieSnapshot *)object;
|
||||
*pSize = sizeof(TrieSnapshot) + snapshot->mem_usage();
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
else if (type == htIntCellTrie)
|
||||
{
|
||||
IntCellTrie *pArray = (IntCellTrie *)object;
|
||||
*pSize = sizeof(IntCellTrie) + pArray->map.mem_usage();
|
||||
return true;
|
||||
}
|
||||
else if (type == htIntSnapshot)
|
||||
{
|
||||
IntTrieSnapshot *snapshot = (IntTrieSnapshot *)object;
|
||||
*pSize = sizeof(IntTrieSnapshot) + snapshot->mem_usage();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
} s_CellTrieHelpers;
|
||||
|
||||
@ -242,6 +294,21 @@ static cell_t CreateTrie(IPluginContext *pContext, const cell_t *params)
|
||||
return hndl;
|
||||
}
|
||||
|
||||
static cell_t CreateIntTrie(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
IntCellTrie *pTrie = new IntCellTrie;
|
||||
Handle_t hndl;
|
||||
|
||||
if ((hndl = handlesys->CreateHandle(htIntCellTrie, pTrie, pContext->GetIdentity(), g_pCoreIdent, NULL))
|
||||
== BAD_HANDLE)
|
||||
{
|
||||
delete pTrie;
|
||||
return BAD_HANDLE;
|
||||
}
|
||||
|
||||
return hndl;
|
||||
}
|
||||
|
||||
static cell_t SetTrieValue(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
CellTrie *pTrie;
|
||||
@ -275,6 +342,38 @@ static cell_t SetTrieValue(IPluginContext *pContext, const cell_t *params)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static cell_t SetIntTrieValue(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
IntCellTrie *pTrie;
|
||||
HandleError err;
|
||||
HandleSecurity sec = HandleSecurity(pContext->GetIdentity(), g_pCoreIdent);
|
||||
|
||||
Handle_t hndl = params[1];
|
||||
|
||||
if ((err = handlesys->ReadHandle(hndl, htIntCellTrie, &sec, (void **)&pTrie))
|
||||
!= HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid Handle %x (error %d)", hndl, err);
|
||||
}
|
||||
|
||||
int32_t key = params[2];
|
||||
|
||||
IntHashMap<Entry>::Insert i = pTrie->map.findForAdd(key);
|
||||
if (!i.found())
|
||||
{
|
||||
if (!pTrie->map.add(i, key))
|
||||
return 0;
|
||||
i->value.setCell(params[3]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!params[4])
|
||||
return 0;
|
||||
|
||||
i->value.setCell(params[3]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static cell_t SetTrieArray(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
CellTrie *pTrie;
|
||||
@ -316,6 +415,46 @@ static cell_t SetTrieArray(IPluginContext *pContext, const cell_t *params)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static cell_t SetIntTrieArray(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
IntCellTrie *pTrie;
|
||||
HandleError err;
|
||||
HandleSecurity sec = HandleSecurity(pContext->GetIdentity(), g_pCoreIdent);
|
||||
|
||||
Handle_t hndl = params[1];
|
||||
|
||||
if ((err = handlesys->ReadHandle(hndl, htIntCellTrie, &sec, (void **)&pTrie))
|
||||
!= HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid Handle %x (error %d)", hndl, err);
|
||||
}
|
||||
|
||||
if (params[4] < 0)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid array size: %d", params[4]);
|
||||
}
|
||||
|
||||
int32_t key = params[2];
|
||||
cell_t *array;
|
||||
pContext->LocalToPhysAddr(params[3], &array);
|
||||
|
||||
IntHashMap<Entry>::Insert i = pTrie->map.findForAdd(key);
|
||||
if (!i.found())
|
||||
{
|
||||
if (!pTrie->map.add(i, key))
|
||||
return 0;
|
||||
i->key = key;
|
||||
i->value.setArray(array, params[4]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!params[5])
|
||||
return 0;
|
||||
|
||||
i->value.setArray(array, params[4]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static cell_t SetTrieString(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
CellTrie *pTrie;
|
||||
@ -350,6 +489,40 @@ static cell_t SetTrieString(IPluginContext *pContext, const cell_t *params)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static cell_t SetIntTrieString(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
IntCellTrie *pTrie;
|
||||
HandleError err;
|
||||
HandleSecurity sec = HandleSecurity(pContext->GetIdentity(), g_pCoreIdent);
|
||||
|
||||
Handle_t hndl = params[1];
|
||||
|
||||
if ((err = handlesys->ReadHandle(hndl, htIntCellTrie, &sec, (void **)&pTrie))
|
||||
!= HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid Handle %x (error %d)", hndl, err);
|
||||
}
|
||||
|
||||
int32_t key = params[2];
|
||||
char *val;
|
||||
pContext->LocalToString(params[3], &val);
|
||||
|
||||
IntHashMap<Entry>::Insert i = pTrie->map.findForAdd(key);
|
||||
if (!i.found())
|
||||
{
|
||||
if (!pTrie->map.add(i, key))
|
||||
return 0;
|
||||
i->value.setString(val);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!params[4])
|
||||
return 0;
|
||||
|
||||
i->value.setString(val);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static cell_t ContainsKeyInTrie(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
CellTrie *pTrie;
|
||||
@ -371,6 +544,26 @@ static cell_t ContainsKeyInTrie(IPluginContext *pContext, const cell_t *params)
|
||||
return r.found() ? 1 : 0;
|
||||
}
|
||||
|
||||
static cell_t ContainsKeyInIntTrie(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
IntCellTrie *pTrie;
|
||||
HandleError err;
|
||||
HandleSecurity sec = HandleSecurity(pContext->GetIdentity(), g_pCoreIdent);
|
||||
|
||||
Handle_t hndl = params[1];
|
||||
|
||||
if ((err = handlesys->ReadHandle(hndl, htIntCellTrie, &sec, (void **)&pTrie)) != HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid Handle %x (error %d)", hndl, err);
|
||||
}
|
||||
|
||||
int32_t key = params[2];
|
||||
|
||||
IntHashMap<Entry>::Result r = pTrie->map.find(key);
|
||||
|
||||
return r.found() ? 1 : 0;
|
||||
}
|
||||
|
||||
static cell_t RemoveFromTrie(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
CellTrie *pTrie;
|
||||
@ -396,6 +589,30 @@ static cell_t RemoveFromTrie(IPluginContext *pContext, const cell_t *params)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static cell_t RemoveFromIntTrie(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
IntCellTrie *pTrie;
|
||||
HandleError err;
|
||||
HandleSecurity sec = HandleSecurity(pContext->GetIdentity(), g_pCoreIdent);
|
||||
|
||||
Handle_t hndl = params[1];
|
||||
|
||||
if ((err = handlesys->ReadHandle(hndl, htIntCellTrie, &sec, (void **)&pTrie))
|
||||
!= HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid Handle %x (error %d)", hndl, err);
|
||||
}
|
||||
|
||||
int32_t key = params[2];
|
||||
|
||||
IntHashMap<Entry>::Result r = pTrie->map.find(key);
|
||||
if (!r.found())
|
||||
return 0;
|
||||
|
||||
pTrie->map.remove(r);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static cell_t ClearTrie(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
Handle_t hndl;
|
||||
@ -415,6 +632,25 @@ static cell_t ClearTrie(IPluginContext *pContext, const cell_t *params)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static cell_t ClearIntTrie(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
Handle_t hndl;
|
||||
IntCellTrie *pTrie;
|
||||
HandleError err;
|
||||
HandleSecurity sec = HandleSecurity(pContext->GetIdentity(), g_pCoreIdent);
|
||||
|
||||
hndl = params[1];
|
||||
|
||||
if ((err = handlesys->ReadHandle(hndl, htIntCellTrie, &sec, (void **)&pTrie))
|
||||
!= HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid Handle %x (error %d)", hndl, err);
|
||||
}
|
||||
|
||||
pTrie->map.clear();
|
||||
return 1;
|
||||
}
|
||||
|
||||
static cell_t GetTrieValue(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
Handle_t hndl;
|
||||
@ -457,6 +693,47 @@ static cell_t GetTrieValue(IPluginContext *pContext, const cell_t *params)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static cell_t GetIntTrieValue(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
Handle_t hndl;
|
||||
IntCellTrie *pTrie;
|
||||
HandleError err;
|
||||
HandleSecurity sec = HandleSecurity(pContext->GetIdentity(), g_pCoreIdent);
|
||||
|
||||
hndl = params[1];
|
||||
|
||||
if ((err = handlesys->ReadHandle(hndl, htIntCellTrie, &sec, (void **)&pTrie))
|
||||
!= HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid Handle %x (error %d)", hndl, err);
|
||||
}
|
||||
|
||||
int32_t key = params[2];
|
||||
cell_t *pValue;
|
||||
pContext->LocalToPhysAddr(params[3], &pValue);
|
||||
|
||||
IntHashMap<Entry>::Result r = pTrie->map.find(key);
|
||||
if (!r.found())
|
||||
return 0;
|
||||
|
||||
if (r->value.isCell())
|
||||
{
|
||||
*pValue = r->value.cell();
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Maintain compatibility with an old bug. If an array was set with one
|
||||
// cell, it was stored internally as a single cell. We now store as an
|
||||
// actual array, but we make GetTrieValue() still work for this case.
|
||||
if (r->value.isArray() && r->value.arrayLength() == 1)
|
||||
{
|
||||
*pValue = r->value.array()[0];
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static cell_t GetTrieArray(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
Handle_t hndl;
|
||||
@ -509,6 +786,56 @@ static cell_t GetTrieArray(IPluginContext *pContext, const cell_t *params)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static cell_t GetIntTrieArray(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
Handle_t hndl;
|
||||
IntCellTrie *pTrie;
|
||||
HandleError err;
|
||||
HandleSecurity sec = HandleSecurity(pContext->GetIdentity(), g_pCoreIdent);
|
||||
|
||||
hndl = params[1];
|
||||
|
||||
if ((err = handlesys->ReadHandle(hndl, htIntCellTrie, &sec, (void **)&pTrie))
|
||||
!= HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid Handle %x (error %d)", hndl, err);
|
||||
}
|
||||
|
||||
if (params[4] < 0)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid array size: %d", params[4]);
|
||||
}
|
||||
|
||||
int32_t key = params[2];
|
||||
cell_t *pValue, *pSize;
|
||||
pContext->LocalToPhysAddr(params[3], &pValue);
|
||||
pContext->LocalToPhysAddr(params[5], &pSize);
|
||||
|
||||
IntHashMap<Entry>::Result r = pTrie->map.find(key);
|
||||
if (!r.found() || !r->value.isArray())
|
||||
return 0;
|
||||
|
||||
if (!r->value.array())
|
||||
{
|
||||
*pSize = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!params[4])
|
||||
return 1;
|
||||
|
||||
size_t length = r->value.arrayLength();
|
||||
cell_t *base = r->value.array();
|
||||
|
||||
if (length > size_t(params[4]))
|
||||
*pSize = params[4];
|
||||
else
|
||||
*pSize = length;
|
||||
|
||||
memcpy(pValue, base, sizeof(cell_t) * pSize[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static cell_t GetTrieString(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
Handle_t hndl;
|
||||
@ -545,6 +872,41 @@ static cell_t GetTrieString(IPluginContext *pContext, const cell_t *params)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static cell_t GetIntTrieString(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
Handle_t hndl;
|
||||
IntCellTrie *pTrie;
|
||||
HandleError err;
|
||||
HandleSecurity sec = HandleSecurity(pContext->GetIdentity(), g_pCoreIdent);
|
||||
|
||||
hndl = params[1];
|
||||
|
||||
if ((err = handlesys->ReadHandle(hndl, htIntCellTrie, &sec, (void **)&pTrie))
|
||||
!= HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid Handle %x (error %d)", hndl, err);
|
||||
}
|
||||
|
||||
if (params[4] < 0)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid buffer size: %d", params[4]);
|
||||
}
|
||||
|
||||
int32_t key = params[2];
|
||||
cell_t *pSize;
|
||||
pContext->LocalToPhysAddr(params[5], &pSize);
|
||||
|
||||
IntHashMap<Entry>::Result r = pTrie->map.find(key);
|
||||
if (!r.found() || !r->value.isString())
|
||||
return 0;
|
||||
|
||||
size_t written;
|
||||
pContext->StringToLocalUTF8(params[3], params[4], r->value.c_str(), &written);
|
||||
|
||||
*pSize = (cell_t)written;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static cell_t GetTrieSize(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
Handle_t hndl;
|
||||
@ -563,6 +925,24 @@ static cell_t GetTrieSize(IPluginContext *pContext, const cell_t *params)
|
||||
return pTrie->map.elements();
|
||||
}
|
||||
|
||||
static cell_t GetIntTrieSize(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
Handle_t hndl;
|
||||
IntCellTrie *pTrie;
|
||||
HandleError err;
|
||||
HandleSecurity sec = HandleSecurity(pContext->GetIdentity(), g_pCoreIdent);
|
||||
|
||||
hndl = params[1];
|
||||
|
||||
if ((err = handlesys->ReadHandle(hndl, htIntCellTrie, &sec, (void **)&pTrie))
|
||||
!= HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid Handle %x (error %d)", hndl, err);
|
||||
}
|
||||
|
||||
return pTrie->map.elements();
|
||||
}
|
||||
|
||||
static cell_t CreateTrieSnapshot(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
HandleError err;
|
||||
@ -595,6 +975,38 @@ static cell_t CreateTrieSnapshot(IPluginContext *pContext, const cell_t *params)
|
||||
return hndl;
|
||||
}
|
||||
|
||||
static cell_t CreateIntTrieSnapshot(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
HandleError err;
|
||||
HandleSecurity sec = HandleSecurity(pContext->GetIdentity(), g_pCoreIdent);
|
||||
|
||||
Handle_t hndl = params[1];
|
||||
|
||||
IntCellTrie *pTrie;
|
||||
if ((err = handlesys->ReadHandle(hndl, htIntCellTrie, &sec, (void **)&pTrie))
|
||||
!= HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid Handle %x (error %d)", hndl, err);
|
||||
}
|
||||
|
||||
IntTrieSnapshot *snapshot = new IntTrieSnapshot;
|
||||
snapshot->length = pTrie->map.elements();
|
||||
snapshot->keys = std::make_unique<int[]>(snapshot->length);
|
||||
size_t i = 0;
|
||||
for (IntHashMap<Entry>::iterator iter = pTrie->map.iter(); !iter.empty(); iter.next(), i++)
|
||||
snapshot->keys[i] = iter->key;
|
||||
assert(i == snapshot->length);
|
||||
|
||||
if ((hndl = handlesys->CreateHandle(htIntSnapshot, snapshot, pContext->GetIdentity(), g_pCoreIdent, NULL))
|
||||
== BAD_HANDLE)
|
||||
{
|
||||
delete snapshot;
|
||||
return BAD_HANDLE;
|
||||
}
|
||||
|
||||
return hndl;
|
||||
}
|
||||
|
||||
static cell_t TrieSnapshotLength(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
HandleError err;
|
||||
@ -612,6 +1024,23 @@ static cell_t TrieSnapshotLength(IPluginContext *pContext, const cell_t *params)
|
||||
return snapshot->length;
|
||||
}
|
||||
|
||||
static cell_t IntTrieSnapshotLength(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
HandleError err;
|
||||
HandleSecurity sec = HandleSecurity(pContext->GetIdentity(), g_pCoreIdent);
|
||||
|
||||
Handle_t hndl = params[1];
|
||||
|
||||
IntTrieSnapshot *snapshot;
|
||||
if ((err = handlesys->ReadHandle(hndl, htIntSnapshot, &sec, (void **)&snapshot))
|
||||
!= HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid Handle %x (error %d)", hndl, err);
|
||||
}
|
||||
|
||||
return snapshot->length;
|
||||
}
|
||||
|
||||
static cell_t TrieSnapshotKeyBufferSize(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
HandleError err;
|
||||
@ -657,6 +1086,27 @@ static cell_t GetTrieSnapshotKey(IPluginContext *pContext, const cell_t *params)
|
||||
return written;
|
||||
}
|
||||
|
||||
static cell_t GetIntTrieSnapshotKey(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
HandleError err;
|
||||
HandleSecurity sec = HandleSecurity(pContext->GetIdentity(), g_pCoreIdent);
|
||||
|
||||
Handle_t hndl = params[1];
|
||||
|
||||
IntTrieSnapshot *snapshot;
|
||||
if ((err = handlesys->ReadHandle(hndl, htIntSnapshot, &sec, (void **)&snapshot))
|
||||
!= HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid Handle %x (error %d)", hndl, err);
|
||||
}
|
||||
|
||||
unsigned index = params[2];
|
||||
if (index >= snapshot->length)
|
||||
return pContext->ThrowNativeError("Invalid index %d", index);
|
||||
|
||||
return snapshot->keys[index];
|
||||
}
|
||||
|
||||
static cell_t CloneTrie(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
HandleError err;
|
||||
@ -707,6 +1157,56 @@ static cell_t CloneTrie(IPluginContext *pContext, const cell_t *params)
|
||||
return hndl;
|
||||
}
|
||||
|
||||
static cell_t CloneIntTrie(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
HandleError err;
|
||||
HandleSecurity sec = HandleSecurity(pContext->GetIdentity(), g_pCoreIdent);
|
||||
|
||||
IntCellTrie *pOldTrie;
|
||||
if ((err = handlesys->ReadHandle(params[1], htIntCellTrie, &sec, (void **)&pOldTrie))
|
||||
!= HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid Handle %x (error %d)", params[1], err);
|
||||
}
|
||||
|
||||
IntCellTrie *pNewTrie = new IntCellTrie;
|
||||
Handle_t hndl = handlesys->CreateHandle(htIntCellTrie, pNewTrie, pContext->GetIdentity(), g_pCoreIdent, NULL);
|
||||
if (!hndl)
|
||||
{
|
||||
delete pNewTrie;
|
||||
return hndl;
|
||||
}
|
||||
|
||||
for (IntHashMap<Entry>::iterator it = pOldTrie->map.iter(); !it.empty(); it.next())
|
||||
{
|
||||
int32_t key = it->key;
|
||||
IntHashMap<Entry>::Insert insert = pNewTrie->map.findForAdd(key);
|
||||
if (pNewTrie->map.add(insert, key))
|
||||
{
|
||||
IntHashMap<Entry>::Result result = pOldTrie->map.find(key);
|
||||
if (result->value.isCell())
|
||||
{
|
||||
insert->value.setCell(result->value.cell());
|
||||
}
|
||||
else if (result->value.isString())
|
||||
{
|
||||
insert->value.setString(result->value.c_str());
|
||||
}
|
||||
else if (result->value.isArray())
|
||||
{
|
||||
insert->value.setArray(result->value.array(), result->value.arrayLength());
|
||||
}
|
||||
else
|
||||
{
|
||||
handlesys->FreeHandle(hndl, NULL);
|
||||
return pContext->ThrowNativeError("Unhandled data type encountered, file a bug and reference pr #852");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return hndl;
|
||||
}
|
||||
|
||||
REGISTER_NATIVES(trieNatives)
|
||||
{
|
||||
{"ClearTrie", ClearTrie},
|
||||
@ -740,9 +1240,26 @@ REGISTER_NATIVES(trieNatives)
|
||||
{"StringMap.Snapshot", CreateTrieSnapshot},
|
||||
{"StringMap.Clone", CloneTrie},
|
||||
|
||||
{"IntMap.IntMap", CreateIntTrie},
|
||||
{"IntMap.Clear", ClearIntTrie},
|
||||
{"IntMap.GetArray", GetIntTrieArray},
|
||||
{"IntMap.GetString", GetIntTrieString},
|
||||
{"IntMap.GetValue", GetIntTrieValue},
|
||||
{"IntMap.ContainsKey", ContainsKeyInIntTrie},
|
||||
{"IntMap.Remove", RemoveFromIntTrie},
|
||||
{"IntMap.SetArray", SetIntTrieArray},
|
||||
{"IntMap.SetString", SetIntTrieString},
|
||||
{"IntMap.SetValue", SetIntTrieValue},
|
||||
{"IntMap.Size.get", GetIntTrieSize},
|
||||
{"IntMap.Snapshot", CreateIntTrieSnapshot},
|
||||
{"IntMap.Clone", CloneIntTrie},
|
||||
|
||||
{"StringMapSnapshot.Length.get", TrieSnapshotLength},
|
||||
{"StringMapSnapshot.KeyBufferSize", TrieSnapshotKeyBufferSize},
|
||||
{"StringMapSnapshot.GetKey", GetTrieSnapshotKey},
|
||||
|
||||
{"IntMapSnapshot.Length.get", IntTrieSnapshotLength},
|
||||
{"IntMapSnapshot.GetKey", GetIntTrieSnapshotKey},
|
||||
|
||||
{NULL, NULL},
|
||||
};
|
||||
|
||||
@ -36,7 +36,7 @@
|
||||
#include "util.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <sm_stringhashmap.h>
|
||||
#include <sm_hashmap.h>
|
||||
|
||||
struct ArgumentInfo {
|
||||
ArgumentInfo() : name()
|
||||
|
||||
@ -53,7 +53,7 @@
|
||||
#include <cdll_int.h>
|
||||
#if SOURCE_ENGINE == SE_CSGO
|
||||
#include <am-hashset.h>
|
||||
#include <sm_stringhashmap.h>
|
||||
#include <sm_hashmap.h>
|
||||
#endif
|
||||
#include "SoundEmitterSystem/isoundemittersystembase.h"
|
||||
|
||||
|
||||
@ -167,6 +167,125 @@ methodmap StringMapSnapshot < Handle
|
||||
public native int GetKey(int index, char[] buffer, int maxlength);
|
||||
};
|
||||
|
||||
methodmap IntMap < Handle
|
||||
{
|
||||
// Creates a hash map. A hash map is a container that can map integers (called
|
||||
// "keys") to arbitrary values (cells, arrays, or strings). Keys in a hash map
|
||||
// are unique. That is, there is at most one entry in the map for a given key.
|
||||
//
|
||||
// Insertion, deletion, and lookup in a hash map are all considered to be fast
|
||||
// operations, amortized to O(1), or constant time.
|
||||
//
|
||||
// The word "Trie" in this API is historical. As of SourceMod 1.6, tries have
|
||||
// been internally replaced with hash tables, which have O(1) insertion time
|
||||
// instead of O(n).
|
||||
//
|
||||
// The IntMap must be freed via delete or CloseHandle().
|
||||
public native IntMap();
|
||||
|
||||
// Clones a hash map, returning a new handle with the same size and data.
|
||||
// This should NOT be confused with CloneHandle. This is a completely new
|
||||
// handle with the same data but no relation to the original. It should be
|
||||
// closed when no longer needed with delete or CloseHandle().
|
||||
//
|
||||
// @return New handle to the cloned hash map
|
||||
public native IntMap Clone();
|
||||
|
||||
// Sets a value in a hash map, either inserting a new entry or replacing an old one.
|
||||
//
|
||||
// @param key Key integer.
|
||||
// @param value Value to store at this key.
|
||||
// @param replace If false, operation will fail if the key is already set.
|
||||
// @return True on success, false on failure.
|
||||
public native bool SetValue(const int key, any value, bool replace=true);
|
||||
|
||||
// Sets an array value in a Map, either inserting a new entry or replacing an old one.
|
||||
//
|
||||
// @param key Key integer.
|
||||
// @param array Array to store.
|
||||
// @param num_items Number of items in the array.
|
||||
// @param replace If false, operation will fail if the key is already set.
|
||||
// @return True on success, false on failure.
|
||||
public native bool SetArray(const int key, const any[] array, int num_items, bool replace=true);
|
||||
|
||||
// Sets a string value in a Map, either inserting a new entry or replacing an old one.
|
||||
//
|
||||
// @param key Key integer.
|
||||
// @param value String to store.
|
||||
// @param replace If false, operation will fail if the key is already set.
|
||||
// @return True on success, false on failure.
|
||||
public native bool SetString(const int key, const char[] value, bool replace=true);
|
||||
|
||||
// Retrieves a value in a Map.
|
||||
//
|
||||
// @param key Key integer.
|
||||
// @param value Variable to store value.
|
||||
// @return True on success. False if the key is not set, or the key is set
|
||||
// as an array or string (not a value).
|
||||
public native bool GetValue(const int key, any &value);
|
||||
|
||||
// Retrieves an array in a Map.
|
||||
//
|
||||
// @param key Key integer.
|
||||
// @param array Buffer to store array.
|
||||
// @param max_size Maximum size of array buffer.
|
||||
// @param size Optional parameter to store the number of elements written to the buffer.
|
||||
// @return True on success. False if the key is not set, or the key is set
|
||||
// as a value or string (not an array).
|
||||
public native bool GetArray(const int key, any[] array, int max_size, int &size=0);
|
||||
|
||||
// Retrieves a string in a Map.
|
||||
//
|
||||
// @param key Key integer.
|
||||
// @param value Buffer to store value.
|
||||
// @param max_size Maximum size of string buffer.
|
||||
// @param size Optional parameter to store the number of bytes written to the buffer.
|
||||
// @return True on success. False if the key is not set, or the key is set
|
||||
// as a value or array (not a string).
|
||||
public native bool GetString(const int key, char[] value, int max_size, int &size=0);
|
||||
|
||||
// Checks whether a key is present in a Map.
|
||||
//
|
||||
// @param key Key integer.
|
||||
// @return True if the key has been found, else false.
|
||||
public native bool ContainsKey(const int key);
|
||||
|
||||
// Removes a key entry from a Map.
|
||||
//
|
||||
// @param key Key integer.
|
||||
// @return True on success, false if the value was never set.
|
||||
public native bool Remove(const int key);
|
||||
|
||||
// Clears all entries from a Map.
|
||||
public native void Clear();
|
||||
|
||||
// Create a snapshot of the map's keys. See IntMapSnapshot.
|
||||
public native IntMapSnapshot Snapshot();
|
||||
|
||||
// Retrieves the number of elements in a map.
|
||||
property int Size {
|
||||
public native get();
|
||||
}
|
||||
};
|
||||
|
||||
// A IntMapSnapshot is created via IntMap.Snapshot(). It captures the
|
||||
// keys on a map so they can be read. Snapshots must be freed with delete or
|
||||
// CloseHandle().
|
||||
methodmap IntMapSnapshot < Handle
|
||||
{
|
||||
// Returns the number of keys in the map snapshot.
|
||||
property int Length {
|
||||
public native get();
|
||||
}
|
||||
|
||||
// Retrieves the key integer of a given key in a map snapshot.
|
||||
//
|
||||
// @param index Key index (starting from 0).
|
||||
// @return The key integer
|
||||
// @error Index out of range.
|
||||
public native int GetKey(int index);
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a hash map. A hash map is a container that can map strings (called
|
||||
* "keys") to arbitrary values (cells, arrays, or strings). Keys in a hash map
|
||||
|
||||
@ -13,6 +13,7 @@ public Plugin:myinfo =
|
||||
public OnPluginStart()
|
||||
{
|
||||
RegServerCmd("test_maps", RunTests);
|
||||
RegServerCmd("test_int_maps", RunIntTests);
|
||||
}
|
||||
|
||||
public Action:RunTests(argc)
|
||||
@ -161,3 +162,189 @@ public Action:RunTests(argc)
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
||||
public Action:RunIntTests(argc)
|
||||
{
|
||||
IntMap map = new IntMap();
|
||||
|
||||
for (new i = 0; i < 64; i++) {
|
||||
if (!map.SetValue(i, i))
|
||||
ThrowError("set map to %d failed", i);
|
||||
|
||||
if (!map.ContainsKey(i))
|
||||
ThrowError("map contains %d failed", i)
|
||||
|
||||
new value;
|
||||
if (!map.GetValue(i, value))
|
||||
ThrowError("get map %d", i);
|
||||
if (value != i)
|
||||
ThrowError("get map %d == %d", i, i);
|
||||
}
|
||||
|
||||
// Setting 17 without replace should fail.
|
||||
new value;
|
||||
if (map.SetValue(17, 999, false))
|
||||
ThrowError("set map 17 should fail");
|
||||
if (!map.GetValue(17, value) || value != 17)
|
||||
ThrowError("value at 17 not correct");
|
||||
if (!map.SetValue(17, 999))
|
||||
ThrowError("set map 17 = 999 should succeed");
|
||||
if (!map.GetValue(17, value) || value != 999)
|
||||
ThrowError("value at 17 not correct");
|
||||
|
||||
// Check size is 64.
|
||||
if (map.Size != 64)
|
||||
ThrowError("map size not 64");
|
||||
|
||||
// Check 100 is not found.
|
||||
int array[64];
|
||||
char string[64];
|
||||
if (map.ContainsKey(100) ||
|
||||
map.GetValue(100, value) ||
|
||||
map.GetArray(100, array, sizeof(array)) ||
|
||||
map.GetString(100, string, sizeof(string)))
|
||||
{
|
||||
ThrowError("map should not have 100");
|
||||
}
|
||||
|
||||
// Check that 17 is not a string or array.
|
||||
if (map.GetArray(17, array, sizeof(array)) ||
|
||||
map.GetString(17, string, sizeof(string)))
|
||||
{
|
||||
ThrowError("entry 17 should not be an array or string");
|
||||
}
|
||||
|
||||
// Strings.
|
||||
if (!map.SetString(17, "hellokitty"))
|
||||
ThrowError("17 should be string");
|
||||
if (!map.GetString(17, string, sizeof(string)) ||
|
||||
strcmp(string, "hellokitty") != 0)
|
||||
{
|
||||
ThrowError("17 should be hellokitty");
|
||||
}
|
||||
if (map.GetValue(17, value) ||
|
||||
map.GetArray(17, array, sizeof(array)))
|
||||
{
|
||||
ThrowError("entry 17 should not be an array or string");
|
||||
}
|
||||
|
||||
// Arrays.
|
||||
new data[5] = { 93, 1, 2, 3, 4 };
|
||||
if (!map.SetArray(17, data, 5))
|
||||
ThrowError("couldn't set 17 to 5-entry array");
|
||||
if (!map.GetArray(17, array, sizeof(array)))
|
||||
ThrowError("couldn't fetch 5-entry array");
|
||||
for (new i = 0; i < 5; i++) {
|
||||
if (data[i] != array[i])
|
||||
ThrowError("17 slot %d should be %d, got %d", i, data[i], array[i]);
|
||||
}
|
||||
if (map.GetValue(17, value) ||
|
||||
map.GetString(17, string, sizeof(string)))
|
||||
{
|
||||
ThrowError("entry 17 should not be a value or string");
|
||||
}
|
||||
|
||||
if (!map.SetArray(17, data, 1))
|
||||
ThrowError("couldn't set 17 to 1-entry array");
|
||||
// Check that we fixed an old bug where 1-entry arrays where cells
|
||||
if (!map.GetArray(17, array, sizeof(array), value))
|
||||
ThrowError("couldn't fetch 1-entry array");
|
||||
if (value != 1)
|
||||
ThrowError("array size mismatch (%d, expected %d)", value, 1);
|
||||
// Check that we maintained backward compatibility.
|
||||
if (!map.GetValue(17, value))
|
||||
ThrowError("backwards compatibility failed");
|
||||
if (value != data[0])
|
||||
ThrowError("wrong value (%d, expected %d)", value, data[0]);
|
||||
|
||||
// Remove "17".
|
||||
if (!map.Remove(17))
|
||||
ThrowError("17 should have been removed");
|
||||
if (map.Remove(17))
|
||||
ThrowError("17 should not exist");
|
||||
if (map.ContainsKey(17) ||
|
||||
map.GetValue(17, value) ||
|
||||
map.GetArray(17, array, sizeof(array)) ||
|
||||
map.GetString(17, string, sizeof(string)))
|
||||
{
|
||||
ThrowError("map should not have a 17");
|
||||
}
|
||||
|
||||
map.Clear();
|
||||
|
||||
if (map.Size)
|
||||
ThrowError("size should be 0");
|
||||
|
||||
map.SetString(42, "time!");
|
||||
map.SetString(84, "bees");
|
||||
map.SetString(126, "egg");
|
||||
|
||||
IntMapSnapshot keys = map.Snapshot();
|
||||
{
|
||||
if (keys.Length != 3)
|
||||
ThrowError("map snapshot length should be 3");
|
||||
|
||||
bool found[3];
|
||||
for (new i = 0; i < keys.Length; i++) {
|
||||
decl key = keys.GetKey(i);
|
||||
|
||||
if (key == 42)
|
||||
found[0] = true;
|
||||
else if (key == 84)
|
||||
found[1] = true;
|
||||
else if (key == 126)
|
||||
found[2] = true;
|
||||
else
|
||||
ThrowError("unexpected key: %d", key);
|
||||
}
|
||||
|
||||
if (!found[0] || !found[1] || !found[2])
|
||||
ThrowError("did not find all keys");
|
||||
}
|
||||
delete keys;
|
||||
|
||||
map.SetValue(10240, 6744);
|
||||
map.SetValue(8, 13);
|
||||
|
||||
new cloneData[5] = { 12, 23, 55, 1, 2 };
|
||||
new cloneArr[5];
|
||||
map.SetArray(9102, cloneData, 5);
|
||||
|
||||
IntMap clone = map.Clone();
|
||||
|
||||
if (clone.Size != map.Size)
|
||||
ThrowError("cloned map size mismatch (%d, expected %d)", clone.Size, map.Size);
|
||||
|
||||
if (!clone.GetString(42, string, sizeof(string)))
|
||||
ThrowError("cloned map entry 42 should be a string");
|
||||
if (strcmp(string, "time!") != 0)
|
||||
ThrowError("cloned map entry 42 should be \"time!\"");
|
||||
if (!clone.GetString(84, string, sizeof(string)))
|
||||
ThrowError("cloned map entry 84 should be a string");
|
||||
if (strcmp(string, "bees") != 0)
|
||||
ThrowError("cloned map entry 84 should be \"bees\"");
|
||||
if (!clone.GetString(126, string, sizeof(string)))
|
||||
ThrowError("cloned map entry 126 should be a string");
|
||||
if (strcmp(string, "egg") != 0)
|
||||
ThrowError("cloned map entry 126 should be \"egg\"");
|
||||
if (!clone.GetValue(10240, value))
|
||||
ThrowError("cloned map entry 10240 should be a value");
|
||||
if (value != 6744)
|
||||
ThrowError("cloned map entry 10240 should be 6744")
|
||||
if (!clone.GetValue(8, value))
|
||||
ThrowError("cloned map entry 8 should be a value");
|
||||
if (value != 13)
|
||||
ThrowError("cloned map entry 8 should be 13")
|
||||
if (!clone.GetArray(9102, cloneArr, 5))
|
||||
ThrowError("cloned map entry 9102 should be an array");
|
||||
for (new i = 0; i < 5; i++) {
|
||||
if (cloneData[i] != cloneArr[i])
|
||||
ThrowError("cloned map entry 9102 slot %d should be %d, got %d", i, cloneData[i], cloneArr[i]);
|
||||
}
|
||||
|
||||
delete clone;
|
||||
|
||||
PrintToServer("All tests passed!");
|
||||
|
||||
delete map;
|
||||
return Plugin_Handled;
|
||||
}
|
||||
@ -98,16 +98,25 @@ namespace detail
|
||||
return key.hash();
|
||||
}
|
||||
};
|
||||
|
||||
struct IntHashMapPolicy
|
||||
{
|
||||
static inline bool matches(const int32_t lookup, const int32_t compare) {
|
||||
return lookup == compare;
|
||||
}
|
||||
static inline uint32_t hash(const int32_t key) {
|
||||
return ke::HashInt32(key);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
class StringHashMap
|
||||
template <typename T, typename KeyStoreType, typename Policy, typename ContainerType, typename KeyLookupType>
|
||||
class HashMap
|
||||
{
|
||||
typedef detail::CharsAndLength CharsAndLength;
|
||||
typedef ke::HashMap<std::string, T, detail::StringHashMapPolicy> Internal;
|
||||
typedef ke::HashMap<KeyStoreType, T, Policy> Internal;
|
||||
|
||||
public:
|
||||
StringHashMap()
|
||||
HashMap()
|
||||
: internal_(ke::SystemAllocatorPolicy()),
|
||||
memory_used_(0)
|
||||
{
|
||||
@ -120,9 +129,9 @@ public:
|
||||
typedef typename Internal::iterator iterator;
|
||||
|
||||
// Some KTrie-like helper functions.
|
||||
bool retrieve(const char *aKey, T *aResult = NULL)
|
||||
bool retrieve(const KeyLookupType &aKey, T *aResult = NULL)
|
||||
{
|
||||
CharsAndLength key(aKey);
|
||||
ContainerType key(aKey);
|
||||
Result r = internal_.find(key);
|
||||
if (!r.found())
|
||||
return false;
|
||||
@ -131,9 +140,9 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
bool retrieve(const char *aKey, T **aResult)
|
||||
bool retrieve(const KeyLookupType &aKey, T **aResult)
|
||||
{
|
||||
CharsAndLength key(aKey);
|
||||
ContainerType key(aKey);
|
||||
Result r = internal_.find(key);
|
||||
if (!r.found())
|
||||
return false;
|
||||
@ -141,23 +150,23 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
Result find(const char *aKey)
|
||||
Result find(const KeyLookupType &aKey)
|
||||
{
|
||||
CharsAndLength key(aKey);
|
||||
ContainerType key(aKey);
|
||||
return internal_.find(key);
|
||||
}
|
||||
|
||||
bool contains(const char *aKey)
|
||||
bool contains(const KeyLookupType &aKey)
|
||||
{
|
||||
CharsAndLength key(aKey);
|
||||
ContainerType key(aKey);
|
||||
Result r = internal_.find(key);
|
||||
return r.found();
|
||||
}
|
||||
|
||||
template <typename UV>
|
||||
bool replace(const char *aKey, UV &&value)
|
||||
bool replace(const KeyLookupType &aKey, UV &&value)
|
||||
{
|
||||
CharsAndLength key(aKey);
|
||||
ContainerType key(aKey);
|
||||
Insert i = internal_.findForAdd(key);
|
||||
if (!i.found())
|
||||
{
|
||||
@ -170,9 +179,9 @@ public:
|
||||
}
|
||||
|
||||
template <typename UV>
|
||||
bool insert(const char *aKey, UV &&value)
|
||||
bool insert(const KeyLookupType &aKey, UV &&value)
|
||||
{
|
||||
CharsAndLength key(aKey);
|
||||
ContainerType key(aKey);
|
||||
Insert i = internal_.findForAdd(key);
|
||||
if (i.found())
|
||||
return false;
|
||||
@ -182,9 +191,9 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
bool remove(const char *aKey)
|
||||
bool remove(const KeyLookupType &aKey)
|
||||
{
|
||||
CharsAndLength key(aKey);
|
||||
ContainerType key(aKey);
|
||||
Result r = internal_.find(key);
|
||||
if (!r.found())
|
||||
return false;
|
||||
@ -219,9 +228,9 @@ public:
|
||||
}
|
||||
|
||||
|
||||
Insert findForAdd(const char *aKey)
|
||||
Insert findForAdd(const KeyLookupType &aKey)
|
||||
{
|
||||
CharsAndLength key(aKey);
|
||||
ContainerType key(aKey);
|
||||
return internal_.findForAdd(key);
|
||||
}
|
||||
|
||||
@ -234,7 +243,7 @@ public:
|
||||
}
|
||||
|
||||
// Only value needs to be set after.
|
||||
bool add(Insert &i, const char *aKey)
|
||||
bool add(Insert &i, const KeyLookupType &aKey)
|
||||
{
|
||||
if (!internal_.add(i, aKey))
|
||||
return false;
|
||||
@ -246,6 +255,12 @@ private:
|
||||
size_t memory_used_;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
using StringHashMap = HashMap<T, std::string, detail::StringHashMapPolicy, detail::CharsAndLength, const char *>;
|
||||
|
||||
template <typename T>
|
||||
using IntHashMap = HashMap<T, int32_t, detail::IntHashMapPolicy, const int32_t, int32_t>;
|
||||
|
||||
}
|
||||
|
||||
#endif // _include_sourcemod_hashtable_h_
|
||||
@ -41,7 +41,7 @@
|
||||
#include <am-allocator-policies.h>
|
||||
#include <am-hashmap.h>
|
||||
#include <am-string.h>
|
||||
#include "sm_stringhashmap.h"
|
||||
#include "sm_hashmap.h"
|
||||
|
||||
namespace SourceMod
|
||||
{
|
||||
|
||||
Loading…
Reference in New Issue
Block a user