tools/gdc/sm_symtable.h
author Nicholas Hastings <skamonkey@gmail.com>
Tue Jul 03 07:51:12 2012 -0400 (2012-07-03)
changeset 3573 440c51204096
parent 3129 76208f2e5ef0
permissions -rw-r--r--
Fixed clientprefs prefab menu double free crash (bug 5374, r=asherkin).
fyrenmoo@3129
     1
/**
fyrenmoo@3129
     2
 * vim: set ts=4 sw=4 tw=99 noet :
fyrenmoo@3129
     3
 * =============================================================================
fyrenmoo@3129
     4
 * SourceMod
fyrenmoo@3129
     5
 * Copyright (C) 2004-2009 AlliedModders LLC.  All rights reserved.
fyrenmoo@3129
     6
 * =============================================================================
fyrenmoo@3129
     7
 *
fyrenmoo@3129
     8
 * This program is free software; you can redistribute it and/or modify it under
fyrenmoo@3129
     9
 * the terms of the GNU General Public License, version 3.0, as published by the
fyrenmoo@3129
    10
 * Free Software Foundation.
fyrenmoo@3129
    11
 * 
fyrenmoo@3129
    12
 * This program is distributed in the hope that it will be useful, but WITHOUT
fyrenmoo@3129
    13
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
fyrenmoo@3129
    14
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
fyrenmoo@3129
    15
 * details.
fyrenmoo@3129
    16
 *
fyrenmoo@3129
    17
 * You should have received a copy of the GNU General Public License along with
fyrenmoo@3129
    18
 * this program.  If not, see <http://www.gnu.org/licenses/>.
fyrenmoo@3129
    19
 *
fyrenmoo@3129
    20
 * As a special exception, AlliedModders LLC gives you permission to link the
fyrenmoo@3129
    21
 * code of this program (as well as its derivative works) to "Half-Life 2," the
fyrenmoo@3129
    22
 * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
fyrenmoo@3129
    23
 * by the Valve Corporation.  You must obey the GNU General Public License in
fyrenmoo@3129
    24
 * all respects for all other code used.  Additionally, AlliedModders LLC grants
fyrenmoo@3129
    25
 * this exception to all derivative works.  AlliedModders LLC defines further
fyrenmoo@3129
    26
 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
fyrenmoo@3129
    27
 * or <http://www.sourcemod.net/license.php>.
fyrenmoo@3129
    28
 */
fyrenmoo@3129
    29
fyrenmoo@3129
    30
#ifndef _INCLUDE_SOURCEMOD_CORE_SYMBOLTABLE_H_
fyrenmoo@3129
    31
#define _INCLUDE_SOURCEMOD_CORE_SYMBOLTABLE_H_
fyrenmoo@3129
    32
fyrenmoo@3129
    33
#include <stdlib.h>
fyrenmoo@3129
    34
#include <string.h>
fyrenmoo@3129
    35
#include <limits.h>
fyrenmoo@3129
    36
fyrenmoo@3129
    37
#define KESTRING_TABLE_START_SIZE 65536
fyrenmoo@3129
    38
fyrenmoo@3129
    39
struct Symbol
fyrenmoo@3129
    40
{
fyrenmoo@3129
    41
	size_t length;
fyrenmoo@3129
    42
	uint32_t hash;
fyrenmoo@3129
    43
	void *address;
fyrenmoo@3129
    44
	Symbol *tbl_next;
fyrenmoo@3129
    45
fyrenmoo@3129
    46
	inline char *buffer()
fyrenmoo@3129
    47
	{
fyrenmoo@3129
    48
		return reinterpret_cast<char *>(this + 1);
fyrenmoo@3129
    49
	}
fyrenmoo@3129
    50
};
fyrenmoo@3129
    51
fyrenmoo@3129
    52
class SymbolTable
fyrenmoo@3129
    53
{
fyrenmoo@3129
    54
public:
fyrenmoo@3129
    55
	~SymbolTable()
fyrenmoo@3129
    56
	{
fyrenmoo@3129
    57
		for (uint32_t i = 0; i < nbuckets; i++)
fyrenmoo@3129
    58
		{
fyrenmoo@3129
    59
			Symbol *sym = buckets[i];
fyrenmoo@3129
    60
			while (sym != NULL)
fyrenmoo@3129
    61
			{
fyrenmoo@3129
    62
				Symbol *next = sym->tbl_next;
fyrenmoo@3129
    63
				free(sym);
fyrenmoo@3129
    64
				sym = next;
fyrenmoo@3129
    65
			}
fyrenmoo@3129
    66
		}
fyrenmoo@3129
    67
		free(buckets);
fyrenmoo@3129
    68
	}
fyrenmoo@3129
    69
fyrenmoo@3129
    70
	bool Initialize()
fyrenmoo@3129
    71
	{
fyrenmoo@3129
    72
		buckets = (Symbol **)malloc(sizeof(Symbol *) * KESTRING_TABLE_START_SIZE);
fyrenmoo@3129
    73
		if (buckets == NULL)
fyrenmoo@3129
    74
		{
fyrenmoo@3129
    75
			return false;
fyrenmoo@3129
    76
		}
fyrenmoo@3129
    77
		memset(buckets, 0, sizeof(Symbol *) * KESTRING_TABLE_START_SIZE);
fyrenmoo@3129
    78
fyrenmoo@3129
    79
		nbuckets = KESTRING_TABLE_START_SIZE;
fyrenmoo@3129
    80
		nused = 0;
fyrenmoo@3129
    81
		bucketmask = KESTRING_TABLE_START_SIZE - 1;
fyrenmoo@3129
    82
		return true;
fyrenmoo@3129
    83
	}
fyrenmoo@3129
    84
fyrenmoo@3129
    85
	static inline uint32_t HashString(const char *data, size_t len)
fyrenmoo@3129
    86
	{
fyrenmoo@3129
    87
		#undef get16bits
fyrenmoo@3129
    88
		#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \
fyrenmoo@3129
    89
				|| defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__)
fyrenmoo@3129
    90
			#define get16bits(d) (*((const uint16_t *) (d)))
fyrenmoo@3129
    91
		#endif
fyrenmoo@3129
    92
		#if !defined (get16bits)
fyrenmoo@3129
    93
			#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8)\
fyrenmoo@3129
    94
											 +(uint32_t)(((const uint8_t *)(d))[0]) )
fyrenmoo@3129
    95
		#endif
fyrenmoo@3129
    96
		uint32_t hash = len, tmp;
fyrenmoo@3129
    97
		int rem;
fyrenmoo@3129
    98
fyrenmoo@3129
    99
		if (len <= 0 || data == NULL)
fyrenmoo@3129
   100
		{
fyrenmoo@3129
   101
			return 0;
fyrenmoo@3129
   102
		}
fyrenmoo@3129
   103
fyrenmoo@3129
   104
		rem = len & 3;
fyrenmoo@3129
   105
		len >>= 2;
fyrenmoo@3129
   106
fyrenmoo@3129
   107
		/* Main loop */
fyrenmoo@3129
   108
		for (;len > 0; len--) {
fyrenmoo@3129
   109
				hash	+= get16bits (data);
fyrenmoo@3129
   110
				tmp		= (get16bits (data+2) << 11) ^ hash;
fyrenmoo@3129
   111
				hash	 = (hash << 16) ^ tmp;
fyrenmoo@3129
   112
				data	+= 2 * sizeof (uint16_t);
fyrenmoo@3129
   113
				hash	+= hash >> 11;
fyrenmoo@3129
   114
		}
fyrenmoo@3129
   115
fyrenmoo@3129
   116
		/* Handle end cases */
fyrenmoo@3129
   117
		switch (rem) {
fyrenmoo@3129
   118
				case 3: hash += get16bits (data);
fyrenmoo@3129
   119
								hash ^= hash << 16;
fyrenmoo@3129
   120
								hash ^= data[sizeof (uint16_t)] << 18;
fyrenmoo@3129
   121
								hash += hash >> 11;
fyrenmoo@3129
   122
								break;
fyrenmoo@3129
   123
				case 2: hash += get16bits (data);
fyrenmoo@3129
   124
								hash ^= hash << 11;
fyrenmoo@3129
   125
								hash += hash >> 17;
fyrenmoo@3129
   126
								break;
fyrenmoo@3129
   127
				case 1: hash += *data;
fyrenmoo@3129
   128
								hash ^= hash << 10;
fyrenmoo@3129
   129
								hash += hash >> 1;
fyrenmoo@3129
   130
		}
fyrenmoo@3129
   131
fyrenmoo@3129
   132
		/* Force "avalanching" of final 127 bits */
fyrenmoo@3129
   133
		hash ^= hash << 3;
fyrenmoo@3129
   134
		hash += hash >> 5;
fyrenmoo@3129
   135
		hash ^= hash << 4;
fyrenmoo@3129
   136
		hash += hash >> 17;
fyrenmoo@3129
   137
		hash ^= hash << 25;
fyrenmoo@3129
   138
		hash += hash >> 6;
fyrenmoo@3129
   139
fyrenmoo@3129
   140
		return hash;
fyrenmoo@3129
   141
fyrenmoo@3129
   142
		#undef get16bits
fyrenmoo@3129
   143
	}
fyrenmoo@3129
   144
fyrenmoo@3129
   145
	Symbol **FindSymbolBucket(const char *str, size_t len, uint32_t hash)
fyrenmoo@3129
   146
	{
fyrenmoo@3129
   147
		uint32_t bucket = hash & bucketmask;
fyrenmoo@3129
   148
		Symbol **pkvs = &buckets[bucket];
fyrenmoo@3129
   149
fyrenmoo@3129
   150
		Symbol *kvs = *pkvs;
fyrenmoo@3129
   151
		while (kvs != NULL)
fyrenmoo@3129
   152
		{
fyrenmoo@3129
   153
			if (len == kvs->length && memcmp(str, kvs->buffer(), len * sizeof(char)) == 0)
fyrenmoo@3129
   154
			{
fyrenmoo@3129
   155
				return pkvs;
fyrenmoo@3129
   156
			}
fyrenmoo@3129
   157
			pkvs = &kvs->tbl_next;
fyrenmoo@3129
   158
			kvs = *pkvs;
fyrenmoo@3129
   159
		}
fyrenmoo@3129
   160
fyrenmoo@3129
   161
		return pkvs;
fyrenmoo@3129
   162
	}
fyrenmoo@3129
   163
fyrenmoo@3129
   164
	void ResizeSymbolTable()
fyrenmoo@3129
   165
	{
fyrenmoo@3129
   166
		uint32_t xnbuckets = nbuckets * 2;
fyrenmoo@3129
   167
		Symbol **xbuckets = (Symbol **)malloc(sizeof(Symbol *) * xnbuckets);
fyrenmoo@3129
   168
		if (xbuckets == NULL)
fyrenmoo@3129
   169
		{
fyrenmoo@3129
   170
			return;
fyrenmoo@3129
   171
		}
fyrenmoo@3129
   172
		memset(xbuckets, 0, sizeof(Symbol *) * xnbuckets);
fyrenmoo@3129
   173
		uint32_t xbucketmask = xnbuckets - 1;
fyrenmoo@3129
   174
		for (uint32_t i = 0; i < nbuckets; i++)
fyrenmoo@3129
   175
		{
fyrenmoo@3129
   176
			Symbol *sym = buckets[i];
fyrenmoo@3129
   177
			while (sym != NULL)
fyrenmoo@3129
   178
			{
fyrenmoo@3129
   179
				Symbol *next = sym->tbl_next;
fyrenmoo@3129
   180
				uint32_t bucket = sym->hash & xbucketmask;
fyrenmoo@3129
   181
				sym->tbl_next = xbuckets[bucket];
fyrenmoo@3129
   182
				xbuckets[bucket] = sym;
fyrenmoo@3129
   183
				sym = next;
fyrenmoo@3129
   184
			}
fyrenmoo@3129
   185
		}
fyrenmoo@3129
   186
		free(buckets);
fyrenmoo@3129
   187
		buckets = xbuckets;
fyrenmoo@3129
   188
		nbuckets = xnbuckets;
fyrenmoo@3129
   189
		bucketmask = xbucketmask;
fyrenmoo@3129
   190
	}
fyrenmoo@3129
   191
fyrenmoo@3129
   192
	Symbol *FindSymbol(const char *str, size_t len)
fyrenmoo@3129
   193
	{
fyrenmoo@3129
   194
		uint32_t hash = HashString(str, len);
fyrenmoo@3129
   195
		Symbol **pkvs = FindSymbolBucket(str, len, hash);
fyrenmoo@3129
   196
		return *pkvs;
fyrenmoo@3129
   197
	}
fyrenmoo@3129
   198
fyrenmoo@3129
   199
	Symbol *InternSymbol(const char* str, size_t len, void *address)
fyrenmoo@3129
   200
	{
fyrenmoo@3129
   201
		uint32_t hash = HashString(str, len);
fyrenmoo@3129
   202
		Symbol **pkvs = FindSymbolBucket(str, len, hash);
fyrenmoo@3129
   203
		if (*pkvs != NULL)
fyrenmoo@3129
   204
		{
fyrenmoo@3129
   205
			return *pkvs;
fyrenmoo@3129
   206
		}
fyrenmoo@3129
   207
fyrenmoo@3129
   208
		Symbol *kvs = (Symbol *)malloc(sizeof(Symbol) + sizeof(char) * (len + 1));
fyrenmoo@3129
   209
		kvs->length = len;
fyrenmoo@3129
   210
		kvs->hash = hash;
fyrenmoo@3129
   211
		kvs->address = address;
fyrenmoo@3129
   212
		kvs->tbl_next = NULL;
fyrenmoo@3129
   213
		memcpy(kvs + 1, str, sizeof(char) * (len + 1));
fyrenmoo@3129
   214
		*pkvs = kvs;
fyrenmoo@3129
   215
		nused++;
fyrenmoo@3129
   216
fyrenmoo@3129
   217
		if (nused > nbuckets && nbuckets <= INT_MAX / 2)
fyrenmoo@3129
   218
		{
fyrenmoo@3129
   219
			ResizeSymbolTable();
fyrenmoo@3129
   220
		}
fyrenmoo@3129
   221
fyrenmoo@3129
   222
		return kvs;
fyrenmoo@3129
   223
	}
fyrenmoo@3129
   224
private:
fyrenmoo@3129
   225
	uint32_t nbuckets;
fyrenmoo@3129
   226
	uint32_t nused;
fyrenmoo@3129
   227
	uint32_t bucketmask;
fyrenmoo@3129
   228
	Symbol **buckets;
fyrenmoo@3129
   229
};
fyrenmoo@3129
   230
fyrenmoo@3129
   231
class AddrTable
fyrenmoo@3129
   232
{
fyrenmoo@3129
   233
public:
fyrenmoo@3129
   234
	~AddrTable()
fyrenmoo@3129
   235
	{
fyrenmoo@3129
   236
		for (uint32_t i = 0; i < nbuckets; i++)
fyrenmoo@3129
   237
		{
fyrenmoo@3129
   238
			Symbol *sym = buckets[i];
fyrenmoo@3129
   239
			while (sym != NULL)
fyrenmoo@3129
   240
			{
fyrenmoo@3129
   241
				Symbol *next = sym->tbl_next;
fyrenmoo@3129
   242
				free(sym);
fyrenmoo@3129
   243
				sym = next;
fyrenmoo@3129
   244
			}
fyrenmoo@3129
   245
		}
fyrenmoo@3129
   246
		free(buckets);
fyrenmoo@3129
   247
	}
fyrenmoo@3129
   248
fyrenmoo@3129
   249
	bool Initialize()
fyrenmoo@3129
   250
	{
fyrenmoo@3129
   251
		buckets = (Symbol **)malloc(sizeof(Symbol *) * KESTRING_TABLE_START_SIZE);
fyrenmoo@3129
   252
		if (buckets == NULL)
fyrenmoo@3129
   253
		{
fyrenmoo@3129
   254
			return false;
fyrenmoo@3129
   255
		}
fyrenmoo@3129
   256
		memset(buckets, 0, sizeof(Symbol *) * KESTRING_TABLE_START_SIZE);
fyrenmoo@3129
   257
fyrenmoo@3129
   258
		nbuckets = KESTRING_TABLE_START_SIZE;
fyrenmoo@3129
   259
		nused = 0;
fyrenmoo@3129
   260
		bucketmask = KESTRING_TABLE_START_SIZE - 1;
fyrenmoo@3129
   261
		return true;
fyrenmoo@3129
   262
	}
fyrenmoo@3129
   263
fyrenmoo@3129
   264
	//Knuth's quick 32-bit integer hash, might not be appropriate but I don't think I care much!
fyrenmoo@3129
   265
	static inline uint32_t HashAddr(void *addr)
fyrenmoo@3129
   266
	{
fyrenmoo@3129
   267
		return (uint32_t)addr * (uint32_t)2654435761u;
fyrenmoo@3129
   268
	}
fyrenmoo@3129
   269
fyrenmoo@3129
   270
	Symbol **FindSymbolBucket(void *addr, uint32_t hash)
fyrenmoo@3129
   271
	{
fyrenmoo@3129
   272
		uint32_t bucket = hash & bucketmask;
fyrenmoo@3129
   273
		Symbol **pkvs = &buckets[bucket];
fyrenmoo@3129
   274
fyrenmoo@3129
   275
		Symbol *kvs = *pkvs;
fyrenmoo@3129
   276
		while (kvs != NULL)
fyrenmoo@3129
   277
		{
fyrenmoo@3129
   278
			if (kvs->address == addr)
fyrenmoo@3129
   279
			{
fyrenmoo@3129
   280
				return pkvs;
fyrenmoo@3129
   281
			}
fyrenmoo@3129
   282
			pkvs = &kvs->tbl_next;
fyrenmoo@3129
   283
			kvs = *pkvs;
fyrenmoo@3129
   284
		}
fyrenmoo@3129
   285
fyrenmoo@3129
   286
		return pkvs;
fyrenmoo@3129
   287
	}
fyrenmoo@3129
   288
fyrenmoo@3129
   289
	void ResizeSymbolTable()
fyrenmoo@3129
   290
	{
fyrenmoo@3129
   291
		uint32_t xnbuckets = nbuckets * 2;
fyrenmoo@3129
   292
		Symbol **xbuckets = (Symbol **)malloc(sizeof(Symbol *) * xnbuckets);
fyrenmoo@3129
   293
		if (xbuckets == NULL)
fyrenmoo@3129
   294
		{
fyrenmoo@3129
   295
			return;
fyrenmoo@3129
   296
		}
fyrenmoo@3129
   297
		memset(xbuckets, 0, sizeof(Symbol *) * xnbuckets);
fyrenmoo@3129
   298
		uint32_t xbucketmask = xnbuckets - 1;
fyrenmoo@3129
   299
		for (uint32_t i = 0; i < nbuckets; i++)
fyrenmoo@3129
   300
		{
fyrenmoo@3129
   301
			Symbol *sym = buckets[i];
fyrenmoo@3129
   302
			while (sym != NULL)
fyrenmoo@3129
   303
			{
fyrenmoo@3129
   304
				Symbol *next = sym->tbl_next;
fyrenmoo@3129
   305
				uint32_t bucket = sym->hash & xbucketmask;
fyrenmoo@3129
   306
				sym->tbl_next = xbuckets[bucket];
fyrenmoo@3129
   307
				xbuckets[bucket] = sym;
fyrenmoo@3129
   308
				sym = next;
fyrenmoo@3129
   309
			}
fyrenmoo@3129
   310
		}
fyrenmoo@3129
   311
		free(buckets);
fyrenmoo@3129
   312
		buckets = xbuckets;
fyrenmoo@3129
   313
		nbuckets = xnbuckets;
fyrenmoo@3129
   314
		bucketmask = xbucketmask;
fyrenmoo@3129
   315
	}
fyrenmoo@3129
   316
fyrenmoo@3129
   317
	Symbol *FindAddr(void *addr)
fyrenmoo@3129
   318
	{
fyrenmoo@3129
   319
		uint32_t hash = HashAddr(addr);
fyrenmoo@3129
   320
		Symbol **pkvs = FindSymbolBucket(addr, hash);
fyrenmoo@3129
   321
		return *pkvs;
fyrenmoo@3129
   322
	}
fyrenmoo@3129
   323
fyrenmoo@3129
   324
	Symbol *InternSymbol(const char* str, size_t len, void *address)
fyrenmoo@3129
   325
	{
fyrenmoo@3129
   326
		uint32_t hash = HashAddr(address);
fyrenmoo@3129
   327
		Symbol **pkvs = FindSymbolBucket(address, hash);
fyrenmoo@3129
   328
		if (*pkvs != NULL)
fyrenmoo@3129
   329
		{
fyrenmoo@3129
   330
			return *pkvs;
fyrenmoo@3129
   331
		}
fyrenmoo@3129
   332
fyrenmoo@3129
   333
		Symbol *kvs = (Symbol *)malloc(sizeof(Symbol) + sizeof(char) * (len + 1));
fyrenmoo@3129
   334
		kvs->length = len;
fyrenmoo@3129
   335
		kvs->hash = hash;
fyrenmoo@3129
   336
		kvs->address = address;
fyrenmoo@3129
   337
		kvs->tbl_next = NULL;
fyrenmoo@3129
   338
		memcpy(kvs + 1, str, sizeof(char) * (len + 1));
fyrenmoo@3129
   339
		*pkvs = kvs;
fyrenmoo@3129
   340
		nused++;
fyrenmoo@3129
   341
fyrenmoo@3129
   342
		if (nused > nbuckets && nbuckets <= INT_MAX / 2)
fyrenmoo@3129
   343
		{
fyrenmoo@3129
   344
			ResizeSymbolTable();
fyrenmoo@3129
   345
		}
fyrenmoo@3129
   346
fyrenmoo@3129
   347
		return kvs;
fyrenmoo@3129
   348
	}
fyrenmoo@3129
   349
private:
fyrenmoo@3129
   350
	uint32_t nbuckets;
fyrenmoo@3129
   351
	uint32_t nused;
fyrenmoo@3129
   352
	uint32_t bucketmask;
fyrenmoo@3129
   353
	Symbol **buckets;
fyrenmoo@3129
   354
};
fyrenmoo@3129
   355
fyrenmoo@3129
   356
#endif //_INCLUDE_SOURCEMOD_CORE_SYMBOLTABLE_H_