diff --git a/amxmodx/msvc10/amxmodx_mm.vcxproj.filters b/amxmodx/msvc10/amxmodx_mm.vcxproj.filters index 88fe2a64..55bddbf8 100644 --- a/amxmodx/msvc10/amxmodx_mm.vcxproj.filters +++ b/amxmodx/msvc10/amxmodx_mm.vcxproj.filters @@ -323,6 +323,9 @@ Header Files + + Header Files + diff --git a/amxmodx/sm_stringhashmap.h b/amxmodx/sm_stringhashmap.h new file mode 100644 index 00000000..39f9c0b0 --- /dev/null +++ b/amxmodx/sm_stringhashmap.h @@ -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 . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#ifndef _include_sourcemod_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 +#include +#include +#include +#include + +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 +class StringHashMap +{ + typedef detail::CharsAndLength CharsAndLength; + typedef ke::HashMap 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_ diff --git a/amxmodx/trie_natives.cpp b/amxmodx/trie_natives.cpp index c4d301ce..e7a885eb 100644 --- a/amxmodx/trie_natives.cpp +++ b/amxmodx/trie_natives.cpp @@ -6,18 +6,10 @@ #include "sm_trie_tpl.h" #include "trie_natives.h" -#ifndef NDEBUG -size_t trie_free_count = 0; -size_t trie_malloc_count = 0; -#endif +using namespace SourceMod; -TrieHandles g_TrieHandles; -typedef KTrie celltrie; +TrieHandles g_TrieHandles; -void triedata_dtor(TrieData *ptr) -{ - ptr->freeCells(); -} // native Trie:TrieCreate(); 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); 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) { - 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; } - t->run_destructor(triedata_dtor); - t->clear(); + t->map.clear(); return 1; } // native TrieSetCell(Trie:handle, const key[], any:value); 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) { - 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; } - TrieData *td = NULL; int len; const char *key = get_amxstring(amx, params[2], 0, len); - if ((td = t->retrieve(key)) == NULL) + StringHashMap::Insert i = t->map.findForAdd(key); + if (!i.found()) { - TrieData dummy; - t->insert(key, dummy); - - td = t->retrieve(key); - - // should never, ever happen - if (td == NULL) + if (!t->map.add(i, key)) { - LogError(amx, AMX_ERR_NATIVE, "Couldn't KTrie::retrieve(), handle: %d", params[1]); return 0; } } - - td->setCell(params[3]); + + i->value.setCell(params[3]); return 1; } // native TrieSetString(Trie:handle, const key[], const data[]); 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) { - 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; } - TrieData *td = NULL; int 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::Insert i = t->map.findForAdd(key); + if (!i.found()) { - TrieData dummy; - t->insert(key, dummy); - td = t->retrieve(key); - - // should never, ever happen - if (td == NULL) + if (!t->map.add(i, key)) { - LogError(amx, AMX_ERR_NATIVE, "Couldn't KTrie::retrieve(), handle: %d", params[1]); return 0; } - } - - td->setString(get_amxaddr(amx, params[3])); + + i->value.setString(value); + return 1; } // native TrieSetArray(Trie:handle, const key[], const any:buffer[], buffsize) 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) { - 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; } - TrieData *td = NULL; int len; const char *key = get_amxstring(amx, params[2], 0, len); - if ((td = t->retrieve(key)) == NULL) + StringHashMap::Insert i = t->map.findForAdd(key); + if (!i.found()) { - TrieData dummy; - t->insert(key, dummy); - td = t->retrieve(key); - - // should never, ever happen - if (td == NULL) + if (!t->map.add(i, key)) { - LogError(amx, AMX_ERR_NATIVE, "Couldn't KTrie::retrieve(), handle: %d", params[1]); return 0; } - } - td->setArray(get_amxaddr(amx, params[3]), params[4]); + i->value.setArray(get_amxaddr(amx, params[3]), params[4]); return 1; } // native bool:TrieGetCell(Trie:handle, const key[], &any:value); 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) { - 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; } - - TrieData *td = NULL; int len; const char *key = get_amxstring(amx, params[2], 0, len); - if ((td = t->retrieve(key)) == NULL) + StringHashMap::Result r = t->map.find(key); + + if (!r.found()) { return 0; } + 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; } // native bool:TrieGetString(Trie:handle, const key[], buff[], len); 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) { - 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; } - - TrieData *td = NULL; int 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]); - if (!td->getString(ptr, params[4])) + StringHashMap::Result r = t->map.find(key); + if (!r.found() || !r->value.isString()) { return 0; } + + set_amxstring_utf8(amx, params[3], r->value.chars(), r->value.arrayLength(), params[4] + 1); // + EOS + return 1; } // native bool:TrieGetArray(Trie:handle, const key[], any:buff[], len); 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) { - 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; } - - TrieData *td = NULL; int 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]); - if (!td->getArray(ptr, params[4])) + size_t size = params[4]; + + StringHashMap::Result r = t->map.find(key); + if (!r.found() || !r->value.isArray()) { 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; } // native bool:TrieKeyExists(Trie:handle, const key[]); 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) { - 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; } - int len; const char *key = get_amxstring(amx, params[2], 0, len); - return t->retrieve(key) != NULL ? 1 : 0; + + return static_cast(t->map.contains(key)); } // native bool:TrieDeleteKey(Trie:handle, const key[]); 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) { - 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; } int len; const char *key = get_amxstring(amx, params[2], 0, len); - TrieData *td = t->retrieve(key); - if (td != NULL) + StringHashMap::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) static cell AMX_NATIVE_CALL TrieDestroy(AMX *amx, cell *params) { cell *ptr = get_amxaddr(amx, params[1]); - celltrie *t = g_TrieHandles.lookup(*ptr); + CellTrie *t = g_TrieHandles.lookup(*ptr); if (t == NULL) { return 0; } - t->run_destructor(triedata_dtor); + if (g_TrieHandles.destroy(*ptr)) { *ptr = 0; 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[] = { { "TrieCreate", TrieCreate }, @@ -306,11 +279,6 @@ AMX_NATIVE_INFO trie_Natives[] = { "TrieKeyExists", TrieKeyExists }, { "TrieDestroy", TrieDestroy }, -#ifndef NDEBUG - { "TrieMallocCount", TrieMallocCount }, - { "TrieFreeCount", TrieFreeCount }, -#endif - { NULL, NULL } }; diff --git a/amxmodx/trie_natives.h b/amxmodx/trie_natives.h index fe7d7345..b575ee68 100644 --- a/amxmodx/trie_natives.h +++ b/amxmodx/trie_natives.h @@ -2,150 +2,145 @@ #define _TRIE_NATIVES_H_ #include "amxmodx.h" -#include "sm_trie_tpl.h" +#include "sm_stringhashmap.h" +#include #include "CVector.h" -#define TRIE_DATA_UNSET 0 -#define TRIE_DATA_CELL 1 -#define TRIE_DATA_STRING 2 -#define TRIE_DATA_ARRAY 3 +using namespace SourceMod; -#ifndef NDEBUG -extern size_t trie_malloc_count; -extern size_t trie_free_count; -#endif - -class TrieData +enum EntryType { -private: - cell *m_data; - cell m_cell; - cell m_cellcount; - int m_type; - - void needCells(cell cellcount) - { - 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(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; - } + EntryType_Cell, + EntryType_CellArray, + EntryType_String, }; +class Entry +{ + struct ArrayInfo + { + size_t length; + size_t maxbytes; + + void *base() { + return this + 1; + } + }; + +public: + Entry() + : control_(0) + { + } + Entry(ke::Moveable 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(raw()->base()); + } + char *chars() const { + //assert(isString()); + return reinterpret_cast(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(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 +{ + StringHashMap map; +}; + +template class TrieHandles { private: - CVector< KTrie< TrieData > *> m_tries; + CVector m_tries; public: TrieHandles() { } @@ -166,7 +161,7 @@ public: m_tries.clear(); } - KTrie *lookup(int handle) + T *lookup(int handle) { handle--; @@ -184,12 +179,12 @@ public: if (m_tries[i] == NULL) { // reuse handle - m_tries[i] = new KTrie; + m_tries[i] = new T; return static_cast(i) + 1; } } - m_tries.push_back(new KTrie); + m_tries.push_back(new T); return m_tries.size(); } bool destroy(int handle) @@ -213,7 +208,7 @@ public: }; -extern TrieHandles g_TrieHandles; +extern TrieHandles g_TrieHandles; extern AMX_NATIVE_INFO trie_Natives[]; #endif diff --git a/plugins/include/celltrie.inc b/plugins/include/celltrie.inc index 2300c6e9..87b292ea 100644 --- a/plugins/include/celltrie.inc +++ b/plugins/include/celltrie.inc @@ -1,5 +1,5 @@ #if defined _celltrie_included -#endinput + #endinput #endif #define _celltrie_included @@ -8,19 +8,137 @@ enum Trie 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(); + +/** + * Clears all entries from a Map. + * + * @param handle Map Handle. + * + * @error Invalid 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); + +/** + * 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[]); + +/** + * 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); +/** + * 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); + +/** + * 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); + +/** + * 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); +/** + * 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[]); + +/** + * 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[]); + +/** + * 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);