ds@2863: /**
ds@2863: * vim: set ts=4 sw=4 tw=99 noet :
ds@2863: * =============================================================================
ds@2863: * SourceMod
ds@2863: * Copyright (C) 2004-2009 AlliedModders LLC. All rights reserved.
ds@2863: * =============================================================================
ds@2863: *
ds@2863: * This program is free software; you can redistribute it and/or modify it under
ds@2863: * the terms of the GNU General Public License, version 3.0, as published by the
ds@2863: * Free Software Foundation.
ds@2863: *
ds@2863: * This program is distributed in the hope that it will be useful, but WITHOUT
ds@2863: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
ds@2863: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
ds@2863: * details.
ds@2863: *
ds@2863: * You should have received a copy of the GNU General Public License along with
ds@2863: * this program. If not, see .
ds@2863: *
ds@2863: * As a special exception, AlliedModders LLC gives you permission to link the
ds@2863: * code of this program (as well as its derivative works) to "Half-Life 2," the
ds@2863: * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
ds@2863: * by the Valve Corporation. You must obey the GNU General Public License in
ds@2863: * all respects for all other code used. Additionally, AlliedModders LLC grants
ds@2863: * this exception to all derivative works. AlliedModders LLC defines further
ds@2863: * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
ds@2863: * or .
ds@2863: */
ds@2863:
ds@2863: #ifndef _INCLUDE_SOURCEMOD_CORE_SYMBOLTABLE_H_
ds@2863: #define _INCLUDE_SOURCEMOD_CORE_SYMBOLTABLE_H_
ds@2863:
ds@2863: #include
ds@2863: #include
ds@2863: #include
ds@2863:
ds@2863: #define KESTRING_TABLE_START_SIZE 65536
ds@2863:
ds@2863: struct Symbol
ds@2863: {
ds@2863: size_t length;
ds@2863: uint32_t hash;
ds@2863: void *address;
ds@2863: Symbol *tbl_next;
ds@2863:
ds@2863: inline char *buffer()
ds@2863: {
ds@2863: return reinterpret_cast(this + 1);
ds@2863: }
ds@2863: };
ds@2863:
ds@2863: class SymbolTable
ds@2863: {
ds@2863: public:
ds@2863: ~SymbolTable()
ds@2863: {
ds@2863: for (uint32_t i = 0; i < nbuckets; i++)
ds@2863: {
ds@2863: Symbol *sym = buckets[i];
ds@2863: while (sym != NULL)
ds@2863: {
ds@2863: Symbol *next = sym->tbl_next;
ds@2863: free(sym);
ds@2863: sym = next;
ds@2863: }
ds@2863: }
ds@2863: free(buckets);
ds@2863: }
ds@2863:
ds@2863: bool Initialize()
ds@2863: {
ds@2863: buckets = (Symbol **)malloc(sizeof(Symbol *) * KESTRING_TABLE_START_SIZE);
ds@2863: if (buckets == NULL)
ds@2863: {
ds@2863: return false;
ds@2863: }
ds@2863: memset(buckets, 0, sizeof(Symbol *) * KESTRING_TABLE_START_SIZE);
ds@2863:
ds@2863: nbuckets = KESTRING_TABLE_START_SIZE;
ds@2863: nused = 0;
ds@2863: bucketmask = KESTRING_TABLE_START_SIZE - 1;
ds@2863: return true;
ds@2863: }
ds@2863:
ds@2863: static inline uint32_t HashString(const char *data, size_t len)
ds@2863: {
ds@2863: #undef get16bits
ds@2863: #if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \
ds@2863: || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__)
ds@2863: #define get16bits(d) (*((const uint16_t *) (d)))
ds@2863: #endif
ds@2863: #if !defined (get16bits)
ds@2863: #define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8)\
ds@2863: +(uint32_t)(((const uint8_t *)(d))[0]) )
ds@2863: #endif
ds@2863: uint32_t hash = len, tmp;
ds@2863: int rem;
ds@2863:
ds@2863: if (len <= 0 || data == NULL)
ds@2863: {
ds@2863: return 0;
ds@2863: }
ds@2863:
ds@2863: rem = len & 3;
ds@2863: len >>= 2;
ds@2863:
ds@2863: /* Main loop */
ds@2863: for (;len > 0; len--) {
ds@2863: hash += get16bits (data);
ds@2863: tmp = (get16bits (data+2) << 11) ^ hash;
ds@2863: hash = (hash << 16) ^ tmp;
ds@2863: data += 2 * sizeof (uint16_t);
ds@2863: hash += hash >> 11;
ds@2863: }
ds@2863:
ds@2863: /* Handle end cases */
ds@2863: switch (rem) {
ds@2863: case 3: hash += get16bits (data);
ds@2863: hash ^= hash << 16;
ds@2863: hash ^= data[sizeof (uint16_t)] << 18;
ds@2863: hash += hash >> 11;
ds@2863: break;
ds@2863: case 2: hash += get16bits (data);
ds@2863: hash ^= hash << 11;
ds@2863: hash += hash >> 17;
ds@2863: break;
ds@2863: case 1: hash += *data;
ds@2863: hash ^= hash << 10;
ds@2863: hash += hash >> 1;
ds@2863: }
ds@2863:
ds@2863: /* Force "avalanching" of final 127 bits */
ds@2863: hash ^= hash << 3;
ds@2863: hash += hash >> 5;
ds@2863: hash ^= hash << 4;
ds@2863: hash += hash >> 17;
ds@2863: hash ^= hash << 25;
ds@2863: hash += hash >> 6;
ds@2863:
ds@2863: return hash;
ds@2863:
ds@2863: #undef get16bits
ds@2863: }
ds@2863:
ds@2863: Symbol **FindSymbolBucket(const char *str, size_t len, uint32_t hash)
ds@2863: {
ds@2863: uint32_t bucket = hash & bucketmask;
ds@2863: Symbol **pkvs = &buckets[bucket];
ds@2863:
ds@2863: Symbol *kvs = *pkvs;
ds@2863: while (kvs != NULL)
ds@2863: {
ds@2863: if (len == kvs->length && memcmp(str, kvs->buffer(), len * sizeof(char)) == 0)
ds@2863: {
ds@2863: return pkvs;
ds@2863: }
ds@2863: pkvs = &kvs->tbl_next;
ds@2863: kvs = *pkvs;
ds@2863: }
ds@2863:
ds@2863: return pkvs;
ds@2863: }
ds@2863:
ds@2863: void ResizeSymbolTable()
ds@2863: {
ds@2863: uint32_t xnbuckets = nbuckets * 2;
ds@2863: Symbol **xbuckets = (Symbol **)malloc(sizeof(Symbol *) * xnbuckets);
ds@2863: if (xbuckets == NULL)
ds@2863: {
ds@2863: return;
ds@2863: }
ds@2863: memset(xbuckets, 0, sizeof(Symbol *) * xnbuckets);
ds@2863: uint32_t xbucketmask = xnbuckets - 1;
ds@2863: for (uint32_t i = 0; i < nbuckets; i++)
ds@2863: {
ds@2863: Symbol *sym = buckets[i];
ds@2863: while (sym != NULL)
ds@2863: {
ds@2863: Symbol *next = sym->tbl_next;
ds@2863: uint32_t bucket = sym->hash & xbucketmask;
ds@2863: sym->tbl_next = xbuckets[bucket];
ds@2863: xbuckets[bucket] = sym;
ds@2863: sym = next;
ds@2863: }
ds@2863: }
ds@2863: free(buckets);
ds@2863: buckets = xbuckets;
ds@2863: nbuckets = xnbuckets;
ds@2863: bucketmask = xbucketmask;
ds@2863: }
ds@2863:
ds@2863: Symbol *FindSymbol(const char *str, size_t len)
ds@2863: {
ds@2863: uint32_t hash = HashString(str, len);
ds@2863: Symbol **pkvs = FindSymbolBucket(str, len, hash);
ds@2863: return *pkvs;
ds@2863: }
ds@2863:
ds@2863: Symbol *InternSymbol(const char* str, size_t len, void *address)
ds@2863: {
ds@2863: uint32_t hash = HashString(str, len);
ds@2863: Symbol **pkvs = FindSymbolBucket(str, len, hash);
ds@2863: if (*pkvs != NULL)
ds@2863: {
ds@2863: return *pkvs;
ds@2863: }
ds@2863:
ds@2863: Symbol *kvs = (Symbol *)malloc(sizeof(Symbol) + sizeof(char) * (len + 1));
ds@2863: kvs->length = len;
ds@2863: kvs->hash = hash;
ds@2863: kvs->address = address;
ds@2863: kvs->tbl_next = NULL;
ds@2863: memcpy(kvs + 1, str, sizeof(char) * (len + 1));
ds@2863: *pkvs = kvs;
ds@2863: nused++;
ds@2863:
ds@2863: if (nused > nbuckets && nbuckets <= INT_MAX / 2)
ds@2863: {
ds@2863: ResizeSymbolTable();
ds@2863: }
ds@2863:
ds@2863: return kvs;
ds@2863: }
ds@2863: private:
ds@2863: uint32_t nbuckets;
ds@2863: uint32_t nused;
ds@2863: uint32_t bucketmask;
ds@2863: Symbol **buckets;
ds@2863: };
ds@2863:
ds@2863: #endif //_INCLUDE_SOURCEMOD_CORE_SYMBOLTABLE_H_