Switch trie_natives off KTrie
This commit is contained in:
parent
f3aee6d766
commit
d933783629
@ -323,6 +323,9 @@
|
|||||||
<ClInclude Include="..\CDataPack.h">
|
<ClInclude Include="..\CDataPack.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\sm_stringhashmap.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ResourceCompile Include="..\version.rc">
|
<ResourceCompile Include="..\version.rc">
|
||||||
|
241
amxmodx/sm_stringhashmap.h
Normal file
241
amxmodx/sm_stringhashmap.h
Normal file
@ -0,0 +1,241 @@
|
|||||||
|
/**
|
||||||
|
* 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_hashtable_h_
|
||||||
|
#define _include_sourcemod_hashtable_h_
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file sm_stringhashmap.h
|
||||||
|
*
|
||||||
|
* @brief Generic Key -> Value map class, based on a hash table. The Key, in
|
||||||
|
* this case, is always an ASCII string, and the value type is a template
|
||||||
|
* parameter. This class is intended as a drop-in replacement for KTrie
|
||||||
|
* (though the retrieve() signature has been improved).
|
||||||
|
*
|
||||||
|
* If your Value type already contains the key string, consider using
|
||||||
|
* NameHashSet instead.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <am-allocator-policies.h>
|
||||||
|
#include <am-hashmap.h>
|
||||||
|
#include <am-string.h>
|
||||||
|
#include <am-moveable.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
namespace SourceMod
|
||||||
|
{
|
||||||
|
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
class CharsAndLength
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CharsAndLength(const char *str)
|
||||||
|
: str_(str),
|
||||||
|
length_(0)
|
||||||
|
{
|
||||||
|
int c;
|
||||||
|
uint32_t hash = 0;
|
||||||
|
while ((c = *str++))
|
||||||
|
hash = c + (hash << 6) + (hash << 16) - hash;
|
||||||
|
hash_ = hash;
|
||||||
|
length_ = str - str_ - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t hash() const {
|
||||||
|
return hash_;
|
||||||
|
}
|
||||||
|
const char *chars() const {
|
||||||
|
return str_;
|
||||||
|
}
|
||||||
|
size_t length() const {
|
||||||
|
return length_;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const char *str_;
|
||||||
|
size_t length_;
|
||||||
|
uint32_t hash_;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct StringHashMapPolicy
|
||||||
|
{
|
||||||
|
static inline bool matches(const CharsAndLength &lookup, const ke::AString &key) {
|
||||||
|
return lookup.length() == key.length() &&
|
||||||
|
memcmp(lookup.chars(), key.chars(), key.length()) == 0;
|
||||||
|
}
|
||||||
|
static inline uint32_t hash(const CharsAndLength &key) {
|
||||||
|
return key.hash();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class StringHashMap
|
||||||
|
{
|
||||||
|
typedef detail::CharsAndLength CharsAndLength;
|
||||||
|
typedef ke::HashMap<ke::AString, T, detail::StringHashMapPolicy> Internal;
|
||||||
|
|
||||||
|
public:
|
||||||
|
StringHashMap()
|
||||||
|
: internal_(ke::SystemAllocatorPolicy()),
|
||||||
|
memory_used_(0)
|
||||||
|
{
|
||||||
|
if (!internal_.init())
|
||||||
|
internal_.reportOutOfMemory();
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef typename Internal::Result Result;
|
||||||
|
typedef typename Internal::Insert Insert;
|
||||||
|
typedef typename Internal::iterator iterator;
|
||||||
|
|
||||||
|
// Some KTrie-like helper functions.
|
||||||
|
bool retrieve(const char *aKey, T *aResult = NULL)
|
||||||
|
{
|
||||||
|
CharsAndLength key(aKey);
|
||||||
|
Result r = internal_.find(key);
|
||||||
|
if (!r.found())
|
||||||
|
return false;
|
||||||
|
if (aResult)
|
||||||
|
*aResult = r->value;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result find(const char *aKey)
|
||||||
|
{
|
||||||
|
CharsAndLength key(aKey);
|
||||||
|
return internal_.find(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool contains(const char *aKey)
|
||||||
|
{
|
||||||
|
CharsAndLength key(aKey);
|
||||||
|
Result r = internal_.find(key);
|
||||||
|
return r.found();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool replace(const char *aKey, const T &value)
|
||||||
|
{
|
||||||
|
CharsAndLength key(aKey);
|
||||||
|
Insert i = internal_.findForAdd(key);
|
||||||
|
if (!i.found())
|
||||||
|
{
|
||||||
|
memory_used_ += key.length() + 1;
|
||||||
|
if (!internal_.add(i))
|
||||||
|
return false;
|
||||||
|
i->key = aKey;
|
||||||
|
}
|
||||||
|
i->value = value;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool insert(const char *aKey, const T &value)
|
||||||
|
{
|
||||||
|
CharsAndLength key(aKey);
|
||||||
|
Insert i = internal_.findForAdd(key);
|
||||||
|
if (i.found())
|
||||||
|
return false;
|
||||||
|
if (!internal_.add(i))
|
||||||
|
return false;
|
||||||
|
memory_used_ += key.length() + 1;
|
||||||
|
i->key = aKey;
|
||||||
|
i->value = value;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool remove(const char *aKey)
|
||||||
|
{
|
||||||
|
CharsAndLength key(aKey);
|
||||||
|
Result r = internal_.find(key);
|
||||||
|
if (!r.found())
|
||||||
|
return false;
|
||||||
|
memory_used_ -= key.length() + 1;
|
||||||
|
internal_.remove(r);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void remove(Result &r)
|
||||||
|
{
|
||||||
|
internal_.remove(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
internal_.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator iter()
|
||||||
|
{
|
||||||
|
return internal_.iter();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t mem_usage() const
|
||||||
|
{
|
||||||
|
return internal_.estimateMemoryUse() + memory_used_;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t elements() const
|
||||||
|
{
|
||||||
|
return internal_.elements();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Insert findForAdd(const char *aKey)
|
||||||
|
{
|
||||||
|
CharsAndLength key(aKey);
|
||||||
|
return internal_.findForAdd(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note that |i->key| must be set after calling this, and the key must
|
||||||
|
// be the same as used with findForAdd(). It is best to avoid these two
|
||||||
|
// functions as the combined variants above are safer.
|
||||||
|
bool add(Insert &i)
|
||||||
|
{
|
||||||
|
return internal_.add(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only value needs to be set after.
|
||||||
|
bool add(Insert &i, const char *aKey)
|
||||||
|
{
|
||||||
|
if (!internal_.add(i))
|
||||||
|
return false;
|
||||||
|
i->key = aKey;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Internal internal_;
|
||||||
|
size_t memory_used_;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // _include_sourcemod_hashtable_h_
|
@ -6,18 +6,10 @@
|
|||||||
#include "sm_trie_tpl.h"
|
#include "sm_trie_tpl.h"
|
||||||
#include "trie_natives.h"
|
#include "trie_natives.h"
|
||||||
|
|
||||||
#ifndef NDEBUG
|
using namespace SourceMod;
|
||||||
size_t trie_free_count = 0;
|
|
||||||
size_t trie_malloc_count = 0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
TrieHandles g_TrieHandles;
|
TrieHandles<CellTrie> g_TrieHandles;
|
||||||
typedef KTrie<TrieData> celltrie;
|
|
||||||
|
|
||||||
void triedata_dtor(TrieData *ptr)
|
|
||||||
{
|
|
||||||
ptr->freeCells();
|
|
||||||
}
|
|
||||||
// native Trie:TrieCreate();
|
// native Trie:TrieCreate();
|
||||||
static cell AMX_NATIVE_CALL TrieCreate(AMX *amx, cell *params)
|
static cell AMX_NATIVE_CALL TrieCreate(AMX *amx, cell *params)
|
||||||
{
|
{
|
||||||
@ -27,268 +19,249 @@ static cell AMX_NATIVE_CALL TrieCreate(AMX *amx, cell *params)
|
|||||||
// native Trie::TrieClear(Trie:handle);
|
// native Trie::TrieClear(Trie:handle);
|
||||||
static cell AMX_NATIVE_CALL TrieClear(AMX *amx, cell *params)
|
static cell AMX_NATIVE_CALL TrieClear(AMX *amx, cell *params)
|
||||||
{
|
{
|
||||||
celltrie *t = g_TrieHandles.lookup(params[1]);
|
CellTrie *t = g_TrieHandles.lookup(params[1]);
|
||||||
|
|
||||||
if (t == NULL)
|
if (t == NULL)
|
||||||
{
|
{
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid trie handle provided (%d)", params[1]);
|
LogError(amx, AMX_ERR_NATIVE, "Invalid map handle provided (%d)", params[1]);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
t->run_destructor(triedata_dtor);
|
t->map.clear();
|
||||||
t->clear();
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
// native TrieSetCell(Trie:handle, const key[], any:value);
|
// native TrieSetCell(Trie:handle, const key[], any:value);
|
||||||
static cell AMX_NATIVE_CALL TrieSetCell(AMX *amx, cell *params)
|
static cell AMX_NATIVE_CALL TrieSetCell(AMX *amx, cell *params)
|
||||||
{
|
{
|
||||||
celltrie *t = g_TrieHandles.lookup(params[1]);
|
CellTrie *t = g_TrieHandles.lookup(params[1]);
|
||||||
|
|
||||||
if (t == NULL)
|
if (t == NULL)
|
||||||
{
|
{
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid trie handle provided (%d)", params[1]);
|
LogError(amx, AMX_ERR_NATIVE, "Invalid map handle provided (%d)", params[1]);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
TrieData *td = NULL;
|
|
||||||
int len;
|
int len;
|
||||||
const char *key = get_amxstring(amx, params[2], 0, len);
|
const char *key = get_amxstring(amx, params[2], 0, len);
|
||||||
|
|
||||||
if ((td = t->retrieve(key)) == NULL)
|
StringHashMap<Entry>::Insert i = t->map.findForAdd(key);
|
||||||
|
if (!i.found())
|
||||||
{
|
{
|
||||||
TrieData dummy;
|
if (!t->map.add(i, key))
|
||||||
t->insert(key, dummy);
|
|
||||||
|
|
||||||
td = t->retrieve(key);
|
|
||||||
|
|
||||||
// should never, ever happen
|
|
||||||
if (td == NULL)
|
|
||||||
{
|
{
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Couldn't KTrie::retrieve(), handle: %d", params[1]);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
td->setCell(params[3]);
|
i->value.setCell(params[3]);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
// native TrieSetString(Trie:handle, const key[], const data[]);
|
// native TrieSetString(Trie:handle, const key[], const data[]);
|
||||||
static cell AMX_NATIVE_CALL TrieSetString(AMX *amx, cell *params)
|
static cell AMX_NATIVE_CALL TrieSetString(AMX *amx, cell *params)
|
||||||
{
|
{
|
||||||
celltrie *t = g_TrieHandles.lookup(params[1]);
|
CellTrie *t = g_TrieHandles.lookup(params[1]);
|
||||||
|
|
||||||
if (t == NULL)
|
if (t == NULL)
|
||||||
{
|
{
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid trie handle provided (%d)", params[1]);
|
LogError(amx, AMX_ERR_NATIVE, "Invalid map handle provided (%d)", params[1]);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
TrieData *td = NULL;
|
|
||||||
int len;
|
int len;
|
||||||
const char *key = get_amxstring(amx, params[2], 0, len);
|
const char *key = get_amxstring(amx, params[2], 0, len);
|
||||||
|
const char *value = get_amxstring(amx, params[3], 1, len);
|
||||||
|
|
||||||
if ((td = t->retrieve(key)) == NULL)
|
StringHashMap<Entry>::Insert i = t->map.findForAdd(key);
|
||||||
|
if (!i.found())
|
||||||
{
|
{
|
||||||
TrieData dummy;
|
if (!t->map.add(i, key))
|
||||||
t->insert(key, dummy);
|
|
||||||
td = t->retrieve(key);
|
|
||||||
|
|
||||||
// should never, ever happen
|
|
||||||
if (td == NULL)
|
|
||||||
{
|
{
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Couldn't KTrie::retrieve(), handle: %d", params[1]);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
td->setString(get_amxaddr(amx, params[3]));
|
i->value.setString(value);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
// native TrieSetArray(Trie:handle, const key[], const any:buffer[], buffsize)
|
// native TrieSetArray(Trie:handle, const key[], const any:buffer[], buffsize)
|
||||||
static cell AMX_NATIVE_CALL TrieSetArray(AMX *amx, cell *params)
|
static cell AMX_NATIVE_CALL TrieSetArray(AMX *amx, cell *params)
|
||||||
{
|
{
|
||||||
celltrie *t = g_TrieHandles.lookup(params[1]);
|
CellTrie *t = g_TrieHandles.lookup(params[1]);
|
||||||
|
|
||||||
if (t == NULL)
|
if (t == NULL)
|
||||||
{
|
{
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid trie handle provided (%d)", params[1]);
|
LogError(amx, AMX_ERR_NATIVE, "Invalid map handle provided (%d)", params[1]);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
TrieData *td = NULL;
|
|
||||||
int len;
|
int len;
|
||||||
const char *key = get_amxstring(amx, params[2], 0, len);
|
const char *key = get_amxstring(amx, params[2], 0, len);
|
||||||
|
|
||||||
if ((td = t->retrieve(key)) == NULL)
|
StringHashMap<Entry>::Insert i = t->map.findForAdd(key);
|
||||||
|
if (!i.found())
|
||||||
{
|
{
|
||||||
TrieData dummy;
|
if (!t->map.add(i, key))
|
||||||
t->insert(key, dummy);
|
|
||||||
td = t->retrieve(key);
|
|
||||||
|
|
||||||
// should never, ever happen
|
|
||||||
if (td == NULL)
|
|
||||||
{
|
{
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Couldn't KTrie::retrieve(), handle: %d", params[1]);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
td->setArray(get_amxaddr(amx, params[3]), params[4]);
|
i->value.setArray(get_amxaddr(amx, params[3]), params[4]);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
// native bool:TrieGetCell(Trie:handle, const key[], &any:value);
|
// native bool:TrieGetCell(Trie:handle, const key[], &any:value);
|
||||||
static cell AMX_NATIVE_CALL TrieGetCell(AMX *amx, cell *params)
|
static cell AMX_NATIVE_CALL TrieGetCell(AMX *amx, cell *params)
|
||||||
{
|
{
|
||||||
celltrie *t = g_TrieHandles.lookup(params[1]);
|
CellTrie *t = g_TrieHandles.lookup(params[1]);
|
||||||
|
|
||||||
if (t == NULL)
|
if (t == NULL)
|
||||||
{
|
{
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid trie handle provided (%d)", params[1]);
|
LogError(amx, AMX_ERR_NATIVE, "Invalid map handle provided (%d)", params[1]);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TrieData *td = NULL;
|
|
||||||
int len;
|
int len;
|
||||||
const char *key = get_amxstring(amx, params[2], 0, len);
|
const char *key = get_amxstring(amx, params[2], 0, len);
|
||||||
|
|
||||||
if ((td = t->retrieve(key)) == NULL)
|
StringHashMap<Entry>::Result r = t->map.find(key);
|
||||||
|
|
||||||
|
if (!r.found())
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
cell *ptr = get_amxaddr(amx, params[3]);
|
cell *ptr = get_amxaddr(amx, params[3]);
|
||||||
if (!td->getCell(ptr))
|
|
||||||
|
if (r->value.isCell())
|
||||||
{
|
{
|
||||||
return 0;
|
*ptr = r->value.cell_();
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
// native bool:TrieGetString(Trie:handle, const key[], buff[], len);
|
// native bool:TrieGetString(Trie:handle, const key[], buff[], len);
|
||||||
static cell AMX_NATIVE_CALL TrieGetString(AMX *amx, cell *params)
|
static cell AMX_NATIVE_CALL TrieGetString(AMX *amx, cell *params)
|
||||||
{
|
{
|
||||||
celltrie *t = g_TrieHandles.lookup(params[1]);
|
CellTrie *t = g_TrieHandles.lookup(params[1]);
|
||||||
|
|
||||||
if (t == NULL)
|
if (t == NULL)
|
||||||
{
|
{
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid trie handle provided (%d)", params[1]);
|
LogError(amx, AMX_ERR_NATIVE, "Invalid map handle provided (%d)", params[1]);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TrieData *td = NULL;
|
|
||||||
int len;
|
int len;
|
||||||
const char *key = get_amxstring(amx, params[2], 0, len);
|
const char *key = get_amxstring(amx, params[2], 0, len);
|
||||||
|
|
||||||
if ((td = t->retrieve(key)) == NULL)
|
StringHashMap<Entry>::Result r = t->map.find(key);
|
||||||
{
|
if (!r.found() || !r->value.isString())
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
cell *ptr = get_amxaddr(amx, params[3]);
|
|
||||||
if (!td->getString(ptr, params[4]))
|
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
set_amxstring_utf8(amx, params[3], r->value.chars(), r->value.arrayLength(), params[4] + 1); // + EOS
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
// native bool:TrieGetArray(Trie:handle, const key[], any:buff[], len);
|
// native bool:TrieGetArray(Trie:handle, const key[], any:buff[], len);
|
||||||
static cell AMX_NATIVE_CALL TrieGetArray(AMX *amx, cell *params)
|
static cell AMX_NATIVE_CALL TrieGetArray(AMX *amx, cell *params)
|
||||||
{
|
{
|
||||||
celltrie *t = g_TrieHandles.lookup(params[1]);
|
CellTrie *t = g_TrieHandles.lookup(params[1]);
|
||||||
|
|
||||||
if (t == NULL)
|
if (t == NULL)
|
||||||
{
|
{
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid trie handle provided (%d)", params[1]);
|
LogError(amx, AMX_ERR_NATIVE, "Invalid map handle provided (%d)", params[1]);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TrieData *td = NULL;
|
|
||||||
int len;
|
int len;
|
||||||
const char *key = get_amxstring(amx, params[2], 0, len);
|
const char *key = get_amxstring(amx, params[2], 0, len);
|
||||||
|
|
||||||
if ((td = t->retrieve(key)) == NULL)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
cell *ptr = get_amxaddr(amx, params[3]);
|
cell *ptr = get_amxaddr(amx, params[3]);
|
||||||
if (!td->getArray(ptr, params[4]))
|
size_t size = params[4];
|
||||||
|
|
||||||
|
StringHashMap<Entry>::Result r = t->map.find(key);
|
||||||
|
if (!r.found() || !r->value.isArray())
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t length = r->value.arrayLength();
|
||||||
|
cell *base = r->value.array();
|
||||||
|
|
||||||
|
if (length <= size)
|
||||||
|
{
|
||||||
|
size = length;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(ptr, base, sizeof(cell)* size);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
// native bool:TrieKeyExists(Trie:handle, const key[]);
|
// native bool:TrieKeyExists(Trie:handle, const key[]);
|
||||||
static cell AMX_NATIVE_CALL TrieKeyExists(AMX *amx, cell *params)
|
static cell AMX_NATIVE_CALL TrieKeyExists(AMX *amx, cell *params)
|
||||||
{
|
{
|
||||||
celltrie *t = g_TrieHandles.lookup(params[1]);
|
CellTrie *t = g_TrieHandles.lookup(params[1]);
|
||||||
|
|
||||||
if (t == NULL)
|
if (t == NULL)
|
||||||
{
|
{
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid trie handle provided (%d)", params[1]);
|
LogError(amx, AMX_ERR_NATIVE, "Invalid map handle provided (%d)", params[1]);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int len;
|
int len;
|
||||||
const char *key = get_amxstring(amx, params[2], 0, len);
|
const char *key = get_amxstring(amx, params[2], 0, len);
|
||||||
return t->retrieve(key) != NULL ? 1 : 0;
|
|
||||||
|
return static_cast<cell>(t->map.contains(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
// native bool:TrieDeleteKey(Trie:handle, const key[]);
|
// native bool:TrieDeleteKey(Trie:handle, const key[]);
|
||||||
static cell AMX_NATIVE_CALL TrieDeleteKey(AMX *amx, cell *params)
|
static cell AMX_NATIVE_CALL TrieDeleteKey(AMX *amx, cell *params)
|
||||||
{
|
{
|
||||||
celltrie *t = g_TrieHandles.lookup(params[1]);
|
CellTrie *t = g_TrieHandles.lookup(params[1]);
|
||||||
|
|
||||||
if (t == NULL)
|
if (t == NULL)
|
||||||
{
|
{
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid trie handle provided (%d)", params[1]);
|
LogError(amx, AMX_ERR_NATIVE, "Invalid map handle provided (%d)", params[1]);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int len;
|
int len;
|
||||||
const char *key = get_amxstring(amx, params[2], 0, len);
|
const char *key = get_amxstring(amx, params[2], 0, len);
|
||||||
TrieData *td = t->retrieve(key);
|
|
||||||
|
|
||||||
if (td != NULL)
|
StringHashMap<Entry>::Result r = t->map.find(key);
|
||||||
|
if (!r.found())
|
||||||
{
|
{
|
||||||
td->freeCells();
|
return 0;
|
||||||
}
|
}
|
||||||
return t->remove(key) ? 1 : 0;
|
|
||||||
|
t->map.remove(r);
|
||||||
|
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
//native TrieDestroy(&Trie:handle)
|
//native TrieDestroy(&Trie:handle)
|
||||||
static cell AMX_NATIVE_CALL TrieDestroy(AMX *amx, cell *params)
|
static cell AMX_NATIVE_CALL TrieDestroy(AMX *amx, cell *params)
|
||||||
{
|
{
|
||||||
cell *ptr = get_amxaddr(amx, params[1]);
|
cell *ptr = get_amxaddr(amx, params[1]);
|
||||||
|
|
||||||
celltrie *t = g_TrieHandles.lookup(*ptr);
|
CellTrie *t = g_TrieHandles.lookup(*ptr);
|
||||||
|
|
||||||
if (t == NULL)
|
if (t == NULL)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
t->run_destructor(triedata_dtor);
|
|
||||||
if (g_TrieHandles.destroy(*ptr))
|
if (g_TrieHandles.destroy(*ptr))
|
||||||
{
|
{
|
||||||
*ptr = 0;
|
*ptr = 0;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return 0;
|
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
#ifndef NDEBUG
|
|
||||||
static cell AMX_NATIVE_CALL TrieMallocCount(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
return trie_malloc_count;
|
|
||||||
}
|
|
||||||
static cell AMX_NATIVE_CALL TrieFreeCount(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
return trie_free_count;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
AMX_NATIVE_INFO trie_Natives[] =
|
AMX_NATIVE_INFO trie_Natives[] =
|
||||||
{
|
{
|
||||||
{ "TrieCreate", TrieCreate },
|
{ "TrieCreate", TrieCreate },
|
||||||
@ -306,11 +279,6 @@ AMX_NATIVE_INFO trie_Natives[] =
|
|||||||
{ "TrieKeyExists", TrieKeyExists },
|
{ "TrieKeyExists", TrieKeyExists },
|
||||||
{ "TrieDestroy", TrieDestroy },
|
{ "TrieDestroy", TrieDestroy },
|
||||||
|
|
||||||
#ifndef NDEBUG
|
|
||||||
{ "TrieMallocCount", TrieMallocCount },
|
|
||||||
{ "TrieFreeCount", TrieFreeCount },
|
|
||||||
#endif
|
|
||||||
|
|
||||||
{ NULL, NULL }
|
{ NULL, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2,150 +2,145 @@
|
|||||||
#define _TRIE_NATIVES_H_
|
#define _TRIE_NATIVES_H_
|
||||||
|
|
||||||
#include "amxmodx.h"
|
#include "amxmodx.h"
|
||||||
#include "sm_trie_tpl.h"
|
#include "sm_stringhashmap.h"
|
||||||
|
#include <am-refcounting.h>
|
||||||
#include "CVector.h"
|
#include "CVector.h"
|
||||||
|
|
||||||
#define TRIE_DATA_UNSET 0
|
using namespace SourceMod;
|
||||||
#define TRIE_DATA_CELL 1
|
|
||||||
#define TRIE_DATA_STRING 2
|
|
||||||
#define TRIE_DATA_ARRAY 3
|
|
||||||
|
|
||||||
#ifndef NDEBUG
|
enum EntryType
|
||||||
extern size_t trie_malloc_count;
|
{
|
||||||
extern size_t trie_free_count;
|
EntryType_Cell,
|
||||||
#endif
|
EntryType_CellArray,
|
||||||
|
EntryType_String,
|
||||||
|
};
|
||||||
|
|
||||||
class TrieData
|
class Entry
|
||||||
{
|
{
|
||||||
private:
|
struct ArrayInfo
|
||||||
cell *m_data;
|
{
|
||||||
cell m_cell;
|
size_t length;
|
||||||
cell m_cellcount;
|
size_t maxbytes;
|
||||||
int m_type;
|
|
||||||
|
|
||||||
void needCells(cell cellcount)
|
void *base() {
|
||||||
{
|
return this + 1;
|
||||||
if (m_cellcount < cellcount)
|
|
||||||
{
|
|
||||||
if (m_data != NULL)
|
|
||||||
{
|
|
||||||
free(m_data);
|
|
||||||
#ifndef NDEBUG
|
|
||||||
trie_free_count++;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
size_t neededbytes = cellcount * sizeof(cell);
|
|
||||||
m_data = static_cast<cell *>(malloc(neededbytes));
|
|
||||||
|
|
||||||
#ifndef NDEBUG
|
|
||||||
trie_malloc_count++;
|
|
||||||
#endif
|
|
||||||
m_cellcount = cellcount;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public:
|
|
||||||
void freeCells()
|
|
||||||
{
|
|
||||||
if (m_data)
|
|
||||||
{
|
|
||||||
#ifndef NDEBUG
|
|
||||||
trie_free_count++;
|
|
||||||
#endif
|
|
||||||
free(m_data);
|
|
||||||
m_data = NULL;
|
|
||||||
}
|
|
||||||
m_cellcount = 0;
|
|
||||||
}
|
|
||||||
TrieData() : m_data(NULL), m_cell(0), m_cellcount(0), m_type(TRIE_DATA_UNSET) { }
|
|
||||||
TrieData(const TrieData &src) : m_data(src.m_data),
|
|
||||||
m_cell(src.m_cell),
|
|
||||||
m_cellcount(src.m_cellcount),
|
|
||||||
m_type(src.m_type) { }
|
|
||||||
~TrieData() { }
|
|
||||||
|
|
||||||
int getType() { return m_type; }
|
|
||||||
|
|
||||||
void setCell(cell value)
|
|
||||||
{
|
|
||||||
freeCells();
|
|
||||||
|
|
||||||
m_cell = value;
|
|
||||||
m_type = TRIE_DATA_CELL;
|
|
||||||
}
|
|
||||||
void setString(cell *value)
|
|
||||||
{
|
|
||||||
cell len = 0;
|
|
||||||
|
|
||||||
cell *p = value;
|
|
||||||
|
|
||||||
while (*p++ != 0)
|
|
||||||
{
|
|
||||||
len++;
|
|
||||||
}
|
|
||||||
len += 1; // zero terminator
|
|
||||||
needCells(len);
|
|
||||||
memcpy(m_data, value, sizeof(cell) * len);
|
|
||||||
|
|
||||||
m_type = TRIE_DATA_STRING;
|
|
||||||
}
|
|
||||||
void setArray(cell *value, cell size)
|
|
||||||
{
|
|
||||||
if (size <= 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
needCells(size);
|
|
||||||
memcpy(m_data, value, sizeof(cell) * size);
|
|
||||||
|
|
||||||
m_type = TRIE_DATA_ARRAY;
|
|
||||||
}
|
|
||||||
bool getCell(cell *out)
|
|
||||||
{
|
|
||||||
if (m_type == TRIE_DATA_CELL)
|
|
||||||
{
|
|
||||||
*out = m_cell;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
bool getString(cell *out, cell max)
|
|
||||||
{
|
|
||||||
if (m_type == TRIE_DATA_STRING && max >= 0)
|
|
||||||
{
|
|
||||||
int len = (max > m_cellcount) ? m_cellcount : max;
|
|
||||||
memcpy(out, m_data, len * sizeof(cell));
|
|
||||||
|
|
||||||
/* Don't truncate a multi-byte character */
|
|
||||||
if (m_data[len - 1] & 1 << 7)
|
|
||||||
{
|
|
||||||
len -= UTIL_CheckValidChar(m_data + len - 1);
|
|
||||||
out[len] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
bool getArray(cell *out, cell max)
|
|
||||||
{
|
|
||||||
if (m_type == TRIE_DATA_ARRAY && max >= 0)
|
|
||||||
{
|
|
||||||
memcpy(out, m_data, (max > m_cellcount ? m_cellcount : max) * sizeof(cell));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
void clear()
|
|
||||||
{
|
|
||||||
freeCells();
|
|
||||||
m_type = TRIE_DATA_UNSET;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
Entry()
|
||||||
|
: control_(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
Entry(ke::Moveable<Entry> other)
|
||||||
|
{
|
||||||
|
control_ = other->control_;
|
||||||
|
data_ = other->data_;
|
||||||
|
other->control_ = 0;
|
||||||
|
}
|
||||||
|
~Entry()
|
||||||
|
{
|
||||||
|
free(raw());
|
||||||
|
}
|
||||||
|
|
||||||
|
void setCell(cell value) {
|
||||||
|
setType(EntryType_Cell);
|
||||||
|
data_ = value;
|
||||||
|
}
|
||||||
|
void setArray(cell *cells, size_t length) {
|
||||||
|
ArrayInfo *array = ensureArray(length * sizeof(cell));
|
||||||
|
array->length = length;
|
||||||
|
memcpy(array->base(), cells, length * sizeof(cell));
|
||||||
|
setTypeAndPointer(EntryType_CellArray, array);
|
||||||
|
}
|
||||||
|
void setString(const char *str) {
|
||||||
|
size_t length = strlen(str);
|
||||||
|
ArrayInfo *array = ensureArray(length + 1);
|
||||||
|
array->length = length;
|
||||||
|
strcpy((char *)array->base(), str);
|
||||||
|
setTypeAndPointer(EntryType_String, array);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t arrayLength() const {
|
||||||
|
//assert(isArray());
|
||||||
|
return raw()->length;
|
||||||
|
}
|
||||||
|
cell *array() const {
|
||||||
|
//assert(isArray());
|
||||||
|
return reinterpret_cast<cell *>(raw()->base());
|
||||||
|
}
|
||||||
|
char *chars() const {
|
||||||
|
//assert(isString());
|
||||||
|
return reinterpret_cast<char *>(raw()->base());
|
||||||
|
}
|
||||||
|
cell cell_() const {
|
||||||
|
//assert(isCell());
|
||||||
|
return data_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isCell() const {
|
||||||
|
return type() == EntryType_Cell;
|
||||||
|
}
|
||||||
|
bool isArray() const {
|
||||||
|
return type() == EntryType_CellArray;
|
||||||
|
}
|
||||||
|
bool isString() const {
|
||||||
|
return type() == EntryType_String;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Entry(const Entry &other) KE_DELETE;
|
||||||
|
|
||||||
|
ArrayInfo *ensureArray(size_t bytes) {
|
||||||
|
ArrayInfo *array = raw();
|
||||||
|
if (array && array->maxbytes >= bytes)
|
||||||
|
return array;
|
||||||
|
array = (ArrayInfo *)realloc(array, bytes + sizeof(ArrayInfo));
|
||||||
|
if (!array)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Out of memory!\n");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
array->maxbytes = bytes;
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pointer and type are overlaid, so we have some accessors.
|
||||||
|
ArrayInfo *raw() const {
|
||||||
|
return reinterpret_cast<ArrayInfo *>(control_ & ~uintptr_t(0x3));
|
||||||
|
}
|
||||||
|
void setType(EntryType aType) {
|
||||||
|
control_ = uintptr_t(raw()) | uintptr_t(aType);
|
||||||
|
//assert(type() == aType);
|
||||||
|
}
|
||||||
|
void setTypeAndPointer(EntryType aType, ArrayInfo *ptr) {
|
||||||
|
// malloc() should guarantee 8-byte alignment at worst
|
||||||
|
//assert((uintptr_t(ptr) & 0x3) == 0);
|
||||||
|
control_ = uintptr_t(ptr) | uintptr_t(aType);
|
||||||
|
//assert(type() == aType);
|
||||||
|
}
|
||||||
|
EntryType type() const {
|
||||||
|
return (EntryType)(control_ & 0x3);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Contains the bits for the type, and an array pointer, if one is set.
|
||||||
|
uintptr_t control_;
|
||||||
|
|
||||||
|
// Contains data for cell-only entries.
|
||||||
|
cell data_;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CellTrie : public ke::Refcounted<CellTrie>
|
||||||
|
{
|
||||||
|
StringHashMap<Entry> map;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
class TrieHandles
|
class TrieHandles
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
CVector< KTrie< TrieData > *> m_tries;
|
CVector<T *> m_tries;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TrieHandles() { }
|
TrieHandles() { }
|
||||||
@ -166,7 +161,7 @@ public:
|
|||||||
|
|
||||||
m_tries.clear();
|
m_tries.clear();
|
||||||
}
|
}
|
||||||
KTrie<TrieData> *lookup(int handle)
|
T *lookup(int handle)
|
||||||
{
|
{
|
||||||
handle--;
|
handle--;
|
||||||
|
|
||||||
@ -184,12 +179,12 @@ public:
|
|||||||
if (m_tries[i] == NULL)
|
if (m_tries[i] == NULL)
|
||||||
{
|
{
|
||||||
// reuse handle
|
// reuse handle
|
||||||
m_tries[i] = new KTrie<TrieData>;
|
m_tries[i] = new T;
|
||||||
|
|
||||||
return static_cast<int>(i) + 1;
|
return static_cast<int>(i) + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_tries.push_back(new KTrie<TrieData>);
|
m_tries.push_back(new T);
|
||||||
return m_tries.size();
|
return m_tries.size();
|
||||||
}
|
}
|
||||||
bool destroy(int handle)
|
bool destroy(int handle)
|
||||||
@ -213,7 +208,7 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
extern TrieHandles g_TrieHandles;
|
extern TrieHandles<CellTrie> g_TrieHandles;
|
||||||
extern AMX_NATIVE_INFO trie_Natives[];
|
extern AMX_NATIVE_INFO trie_Natives[];
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -8,19 +8,137 @@ enum Trie
|
|||||||
Invalid_Trie = 0
|
Invalid_Trie = 0
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
* 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 AMX Mod X 1.8.3, tries have
|
||||||
|
* been internally replaced with hash tables, which have O(1) insertion time
|
||||||
|
* instead of O(n).
|
||||||
|
*
|
||||||
|
* @return New Map Handle, which must be freed via TrieDestroy().
|
||||||
|
*/
|
||||||
native Trie:TrieCreate();
|
native Trie:TrieCreate();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears all entries from a Map.
|
||||||
|
*
|
||||||
|
* @param handle Map Handle.
|
||||||
|
*
|
||||||
|
* @error Invalid Handle.
|
||||||
|
*/
|
||||||
native TrieClear(Trie:handle);
|
native TrieClear(Trie:handle);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a value in a hash map, either inserting a new entry or replacing an old one.
|
||||||
|
*
|
||||||
|
* @param handle Map Handle.
|
||||||
|
* @param key Key string.
|
||||||
|
* @param value Value to store at this key.
|
||||||
|
*
|
||||||
|
* @return True on success, false on failure.
|
||||||
|
* @error Invalid Handle.
|
||||||
|
*/
|
||||||
native TrieSetCell(Trie:handle, const key[], any:value);
|
native TrieSetCell(Trie:handle, const key[], any:value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a string value in a Map, either inserting a new entry or replacing an old one.
|
||||||
|
*
|
||||||
|
* @param handle Map Handle.
|
||||||
|
* @param key Key string.
|
||||||
|
* @param value String to store.
|
||||||
|
*
|
||||||
|
* @return True on success, false on failure.
|
||||||
|
* @error Invalid Handle.
|
||||||
|
*/
|
||||||
native TrieSetString(Trie:handle, const key[], const value[]);
|
native TrieSetString(Trie:handle, const key[], const value[]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets an array value in a Map, either inserting a new entry or replacing an old one.
|
||||||
|
*
|
||||||
|
* @param handle Map Handle.
|
||||||
|
* @param key Key string.
|
||||||
|
* @param buffer Array to store.
|
||||||
|
* @param size Number of items in the array.
|
||||||
|
*
|
||||||
|
* @return True on success, false on failure.
|
||||||
|
* @error Invalid Handle.
|
||||||
|
*/
|
||||||
native TrieSetArray(Trie:handle, const key[], const any:buffer[], size);
|
native TrieSetArray(Trie:handle, const key[], const any:buffer[], size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves a value in a Map.
|
||||||
|
*
|
||||||
|
* @param handle Map Handle.
|
||||||
|
* @param key Key string.
|
||||||
|
* @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).
|
||||||
|
* @error Invalid Handle.
|
||||||
|
*/
|
||||||
native bool:TrieGetCell(Trie:handle, const key[], &any:value);
|
native bool:TrieGetCell(Trie:handle, const key[], &any:value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves a string in a Map.
|
||||||
|
*
|
||||||
|
* @param handle Map Handle.
|
||||||
|
* @param key Key string.
|
||||||
|
* @param output Buffer to store value.
|
||||||
|
* @param outputsize Maximum size of string 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).
|
||||||
|
* @error Invalid Handle.
|
||||||
|
*/
|
||||||
native bool:TrieGetString(Trie:handle, const key[], output[], outputsize);
|
native bool:TrieGetString(Trie:handle, const key[], output[], outputsize);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves an array in a Map.
|
||||||
|
*
|
||||||
|
* @param handle Map Handle.
|
||||||
|
* @param key Key string.
|
||||||
|
* @param output Buffer to store array.
|
||||||
|
* @param outputsize Maximum size of array 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).
|
||||||
|
* @error Invalid Handle.
|
||||||
|
*/
|
||||||
native bool:TrieGetArray(Trie:handle, const key[], any:output[], outputsize);
|
native bool:TrieGetArray(Trie:handle, const key[], any:output[], outputsize);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a key entry from a Map.
|
||||||
|
*
|
||||||
|
* @param handle Map Handle.
|
||||||
|
* @param key Key string.
|
||||||
|
*
|
||||||
|
* @return True on success, false if the value was never set.
|
||||||
|
* @error Invalid Handle.
|
||||||
|
*/
|
||||||
native bool:TrieDeleteKey(Trie:handle, const key[]);
|
native bool:TrieDeleteKey(Trie:handle, const key[]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks a key entry existence from a Map.
|
||||||
|
*
|
||||||
|
* @param handle Map Handle.
|
||||||
|
* @param key Key string.
|
||||||
|
*
|
||||||
|
* @return True on success, false if the value was never set.
|
||||||
|
* @error Invalid Handle.
|
||||||
|
*/
|
||||||
native bool:TrieKeyExists(Trie:handle, const key[]);
|
native bool:TrieKeyExists(Trie:handle, const key[]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destroys a Map.
|
||||||
|
*
|
||||||
|
* @param handle Map Handle.
|
||||||
|
*
|
||||||
|
* @return True on success, false if the value was never set.
|
||||||
|
* @error Invalid Handle.
|
||||||
|
*/
|
||||||
native TrieDestroy(&Trie:handle);
|
native TrieDestroy(&Trie:handle);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user