Switch trie_natives off KTrie

This commit is contained in:
Arkshine
2014-05-03 13:22:48 +02:00
parent f3aee6d766
commit d933783629
5 changed files with 576 additions and 251 deletions

View File

@@ -2,150 +2,145 @@
#define _TRIE_NATIVES_H_
#include "amxmodx.h"
#include "sm_trie_tpl.h"
#include "sm_stringhashmap.h"
#include <am-refcounting.h>
#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<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;
}
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<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
{
private:
CVector< KTrie< TrieData > *> m_tries;
CVector<T *> m_tries;
public:
TrieHandles() { }
@@ -166,7 +161,7 @@ public:
m_tries.clear();
}
KTrie<TrieData> *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<TrieData>;
m_tries[i] = new T;
return static_cast<int>(i) + 1;
}
}
m_tries.push_back(new KTrie<TrieData>);
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<CellTrie> g_TrieHandles;
extern AMX_NATIVE_INFO trie_Natives[];
#endif