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);
| | |