Use hash table for global name lookups (bug 4496, r=fyren).
This commit is contained in:
parent
651dfb796c
commit
fdd1a9afef
@ -53,7 +53,8 @@ files = [
|
|||||||
'zlib/inftrees.c',
|
'zlib/inftrees.c',
|
||||||
'zlib/trees.c',
|
'zlib/trees.c',
|
||||||
'zlib/uncompr.c',
|
'zlib/uncompr.c',
|
||||||
'zlib/zutil.c'
|
'zlib/zutil.c',
|
||||||
|
'sp_symhash.c'
|
||||||
]
|
]
|
||||||
if AMBuild.target['platform'] == 'linux':
|
if AMBuild.target['platform'] == 'linux':
|
||||||
files.append('binreloc.c')
|
files.append('binreloc.c')
|
||||||
|
@ -565,7 +565,6 @@ SC_FUNC void delete_symbol(symbol *root,symbol *sym);
|
|||||||
SC_FUNC void delete_symbols(symbol *root,int level,int del_labels,int delete_functions);
|
SC_FUNC void delete_symbols(symbol *root,int level,int del_labels,int delete_functions);
|
||||||
SC_FUNC int refer_symbol(symbol *entry,symbol *bywhom);
|
SC_FUNC int refer_symbol(symbol *entry,symbol *bywhom);
|
||||||
SC_FUNC void markusage(symbol *sym,int usage);
|
SC_FUNC void markusage(symbol *sym,int usage);
|
||||||
SC_FUNC uint32_t namehash(const char *name);
|
|
||||||
SC_FUNC symbol *findglb(const char *name,int filter);
|
SC_FUNC symbol *findglb(const char *name,int filter);
|
||||||
SC_FUNC symbol *findloc(const char *name);
|
SC_FUNC symbol *findloc(const char *name);
|
||||||
SC_FUNC symbol *findconst(const char *name,int *matchtag);
|
SC_FUNC symbol *findconst(const char *name,int *matchtag);
|
||||||
@ -771,6 +770,8 @@ SC_FUNC int state_conflict_id(int listid1,int listid2);
|
|||||||
|
|
||||||
/* external variables (defined in scvars.c) */
|
/* external variables (defined in scvars.c) */
|
||||||
#if !defined SC_SKIP_VDECL
|
#if !defined SC_SKIP_VDECL
|
||||||
|
typedef struct HashTable HashTable;
|
||||||
|
SC_VDECL struct HashTable *sp_Globals;
|
||||||
SC_VDECL symbol loctab; /* local symbol table */
|
SC_VDECL symbol loctab; /* local symbol table */
|
||||||
SC_VDECL symbol glbtab; /* global symbol table */
|
SC_VDECL symbol glbtab; /* global symbol table */
|
||||||
SC_VDECL cell *litq; /* the literal queue */
|
SC_VDECL cell *litq; /* the literal queue */
|
||||||
|
@ -68,6 +68,7 @@
|
|||||||
#include "sc.h"
|
#include "sc.h"
|
||||||
#include <sourcemod_version.h>
|
#include <sourcemod_version.h>
|
||||||
#include "sctracker.h"
|
#include "sctracker.h"
|
||||||
|
#include "sp_symhash.h"
|
||||||
#define VERSION_STR "3.2.3636"
|
#define VERSION_STR "3.2.3636"
|
||||||
#define VERSION_INT 0x0302
|
#define VERSION_INT 0x0302
|
||||||
|
|
||||||
@ -208,6 +209,10 @@ int pc_compile(int argc, char *argv[])
|
|||||||
if ((jmpcode=setjmp(errbuf))!=0)
|
if ((jmpcode=setjmp(errbuf))!=0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
|
sp_Globals = NewHashTable();
|
||||||
|
if (!sp_Globals)
|
||||||
|
error(123);
|
||||||
|
|
||||||
/* allocate memory for fixed tables */
|
/* allocate memory for fixed tables */
|
||||||
inpfname=(char*)malloc(_MAX_PATH);
|
inpfname=(char*)malloc(_MAX_PATH);
|
||||||
if (inpfname==NULL)
|
if (inpfname==NULL)
|
||||||
@ -511,6 +516,7 @@ cleanup:
|
|||||||
delete_symbols(&loctab,0,TRUE,TRUE); /* delete local variables if not yet
|
delete_symbols(&loctab,0,TRUE,TRUE); /* delete local variables if not yet
|
||||||
* done (i.e. on a fatal error) */
|
* done (i.e. on a fatal error) */
|
||||||
delete_symbols(&glbtab,0,TRUE,TRUE);
|
delete_symbols(&glbtab,0,TRUE,TRUE);
|
||||||
|
DestroyHashTable(sp_Globals);
|
||||||
delete_consttable(&tagname_tab);
|
delete_consttable(&tagname_tab);
|
||||||
delete_consttable(&libname_tab);
|
delete_consttable(&libname_tab);
|
||||||
delete_consttable(&sc_automaton_tab);
|
delete_consttable(&sc_automaton_tab);
|
||||||
@ -3837,8 +3843,10 @@ static int operatoradjust(int opertok,symbol *sym,char *opername,int resulttag)
|
|||||||
refer_symbol(sym,oldsym->refer[i]);
|
refer_symbol(sym,oldsym->refer[i]);
|
||||||
delete_symbol(&glbtab,oldsym);
|
delete_symbol(&glbtab,oldsym);
|
||||||
} /* if */
|
} /* if */
|
||||||
|
RemoveFromHashTable(sp_Globals, sym);
|
||||||
strcpy(sym->name,tmpname);
|
strcpy(sym->name,tmpname);
|
||||||
sym->hash=namehash(sym->name);/* calculate new hash */
|
sym->hash=NameHash(sym->name);/* calculate new hash */
|
||||||
|
AddToHashTable(sp_Globals, sym);
|
||||||
|
|
||||||
/* operators should return a value, except the '~' operator */
|
/* operators should return a value, except the '~' operator */
|
||||||
if (opertok!='~')
|
if (opertok!='~')
|
||||||
|
@ -31,6 +31,7 @@
|
|||||||
#if defined LINUX || defined __FreeBSD__ || defined __OpenBSD__
|
#if defined LINUX || defined __FreeBSD__ || defined __OpenBSD__
|
||||||
#include <sclinux.h>
|
#include <sclinux.h>
|
||||||
#endif
|
#endif
|
||||||
|
#include "sp_symhash.h"
|
||||||
|
|
||||||
#if defined FORTIFY
|
#if defined FORTIFY
|
||||||
#include <alloc/fortify.h>
|
#include <alloc/fortify.h>
|
||||||
@ -2392,6 +2393,7 @@ SC_FUNC int ishex(char c)
|
|||||||
static symbol *add_symbol(symbol *root,symbol *entry,int sort)
|
static symbol *add_symbol(symbol *root,symbol *entry,int sort)
|
||||||
{
|
{
|
||||||
symbol *newsym;
|
symbol *newsym;
|
||||||
|
int global = root==&glbtab;
|
||||||
|
|
||||||
if (sort)
|
if (sort)
|
||||||
while (root->next!=NULL && strcmp(entry->name,root->next->name)>0)
|
while (root->next!=NULL && strcmp(entry->name,root->next->name)>0)
|
||||||
@ -2404,6 +2406,8 @@ static symbol *add_symbol(symbol *root,symbol *entry,int sort)
|
|||||||
memcpy(newsym,entry,sizeof(symbol));
|
memcpy(newsym,entry,sizeof(symbol));
|
||||||
newsym->next=root->next;
|
newsym->next=root->next;
|
||||||
root->next=newsym;
|
root->next=newsym;
|
||||||
|
if (global)
|
||||||
|
AddToHashTable(sp_Globals, newsym);
|
||||||
return newsym;
|
return newsym;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2453,6 +2457,7 @@ static void free_symbol(symbol *sym)
|
|||||||
|
|
||||||
SC_FUNC void delete_symbol(symbol *root,symbol *sym)
|
SC_FUNC void delete_symbol(symbol *root,symbol *sym)
|
||||||
{
|
{
|
||||||
|
symbol *origRoot=root;
|
||||||
/* find the symbol and its predecessor
|
/* find the symbol and its predecessor
|
||||||
* (this function assumes that you will never delete a symbol that is not
|
* (this function assumes that you will never delete a symbol that is not
|
||||||
* in the table pointed at by "root")
|
* in the table pointed at by "root")
|
||||||
@ -2463,6 +2468,9 @@ SC_FUNC void delete_symbol(symbol *root,symbol *sym)
|
|||||||
assert(root!=NULL);
|
assert(root!=NULL);
|
||||||
} /* while */
|
} /* while */
|
||||||
|
|
||||||
|
if (origRoot==&glbtab)
|
||||||
|
RemoveFromHashTable(sp_Globals, sym);
|
||||||
|
|
||||||
/* unlink it, then free it */
|
/* unlink it, then free it */
|
||||||
root->next=sym->next;
|
root->next=sym->next;
|
||||||
free_symbol(sym);
|
free_symbol(sym);
|
||||||
@ -2470,6 +2478,7 @@ SC_FUNC void delete_symbol(symbol *root,symbol *sym)
|
|||||||
|
|
||||||
SC_FUNC void delete_symbols(symbol *root,int level,int delete_labels,int delete_functions)
|
SC_FUNC void delete_symbols(symbol *root,int level,int delete_labels,int delete_functions)
|
||||||
{
|
{
|
||||||
|
symbol *origRoot=root;
|
||||||
symbol *sym,*parent_sym;
|
symbol *sym,*parent_sym;
|
||||||
constvalue *stateptr;
|
constvalue *stateptr;
|
||||||
int mustdelete;
|
int mustdelete;
|
||||||
@ -2525,6 +2534,8 @@ SC_FUNC void delete_symbols(symbol *root,int level,int delete_labels,int delete_
|
|||||||
break;
|
break;
|
||||||
} /* switch */
|
} /* switch */
|
||||||
if (mustdelete) {
|
if (mustdelete) {
|
||||||
|
if (origRoot == &glbtab)
|
||||||
|
RemoveFromHashTable(sp_Globals, sym);
|
||||||
root->next=sym->next;
|
root->next=sym->next;
|
||||||
free_symbol(sym);
|
free_symbol(sym);
|
||||||
} else {
|
} else {
|
||||||
@ -2549,26 +2560,12 @@ SC_FUNC void delete_symbols(symbol *root,int level,int delete_labels,int delete_
|
|||||||
} /* if */
|
} /* if */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The purpose of the hash is to reduce the frequency of a "name"
|
|
||||||
* comparison (which is costly). There is little interest in avoiding
|
|
||||||
* clusters in similar names, which is why this function is plain simple.
|
|
||||||
*/
|
|
||||||
SC_FUNC uint32_t namehash(const char *name)
|
|
||||||
{
|
|
||||||
const unsigned char *ptr=(const unsigned char *)name;
|
|
||||||
int len=strlen(name);
|
|
||||||
if (len==0)
|
|
||||||
return 0L;
|
|
||||||
assert(len<256);
|
|
||||||
return (len<<24Lu) + (ptr[0]<<16Lu) + (ptr[len-1]<<8Lu) + (ptr[len>>1Lu]);
|
|
||||||
}
|
|
||||||
|
|
||||||
static symbol *find_symbol(const symbol *root,const char *name,int fnumber,int automaton,int *cmptag)
|
static symbol *find_symbol(const symbol *root,const char *name,int fnumber,int automaton,int *cmptag)
|
||||||
{
|
{
|
||||||
symbol *firstmatch=NULL;
|
symbol *firstmatch=NULL;
|
||||||
symbol *sym=root->next;
|
symbol *sym=root->next;
|
||||||
int count=0;
|
int count=0;
|
||||||
unsigned long hash=namehash(name);
|
unsigned long hash=NameHash(name);
|
||||||
while (sym!=NULL) {
|
while (sym!=NULL) {
|
||||||
if (hash==sym->hash && strcmp(name,sym->name)==0 /* check name */
|
if (hash==sym->hash && strcmp(name,sym->name)==0 /* check name */
|
||||||
&& (sym->parent==NULL || sym->ident==iCONSTEXPR) /* sub-types (hierarchical types) are skipped, except for enum fields */
|
&& (sym->parent==NULL || sym->ident==iCONSTEXPR) /* sub-types (hierarchical types) are skipped, except for enum fields */
|
||||||
@ -2705,7 +2702,7 @@ SC_FUNC symbol *findglb(const char *name,int filter)
|
|||||||
* that has no state(s) attached to it
|
* that has no state(s) attached to it
|
||||||
*/
|
*/
|
||||||
if (sym==NULL)
|
if (sym==NULL)
|
||||||
sym=find_symbol(&glbtab,name,fcurrent,-1,NULL);
|
sym=FindInHashTable(sp_Globals,name,fcurrent);
|
||||||
return sym;
|
return sym;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2724,8 +2721,12 @@ SC_FUNC symbol *findconst(const char *name,int *cmptag)
|
|||||||
symbol *sym;
|
symbol *sym;
|
||||||
|
|
||||||
sym=find_symbol(&loctab,name,-1,-1,cmptag); /* try local symbols first */
|
sym=find_symbol(&loctab,name,-1,-1,cmptag); /* try local symbols first */
|
||||||
if (sym==NULL || sym->ident!=iCONSTEXPR) /* not found, or not a constant */
|
if (sym==NULL || sym->ident!=iCONSTEXPR) { /* not found, or not a constant */
|
||||||
sym=find_symbol(&glbtab,name,fcurrent,-1,cmptag);
|
if (cmptag)
|
||||||
|
sym=FindTaggedInHashTable(sp_Globals,name,fcurrent,cmptag);
|
||||||
|
else
|
||||||
|
sym=FindInHashTable(sp_Globals,name,fcurrent);
|
||||||
|
}
|
||||||
if (sym==NULL || sym->ident!=iCONSTEXPR)
|
if (sym==NULL || sym->ident!=iCONSTEXPR)
|
||||||
return NULL;
|
return NULL;
|
||||||
assert(sym->parent==NULL || (sym->usage & uENUMFIELD)!=0);
|
assert(sym->parent==NULL || (sym->usage & uENUMFIELD)!=0);
|
||||||
@ -2765,7 +2766,7 @@ SC_FUNC symbol *addsym(const char *name,cell addr,int ident,int vclass,int tag,i
|
|||||||
/* first fill in the entry */
|
/* first fill in the entry */
|
||||||
memset(&entry,0,sizeof entry);
|
memset(&entry,0,sizeof entry);
|
||||||
strcpy(entry.name,name);
|
strcpy(entry.name,name);
|
||||||
entry.hash=namehash(name);
|
entry.hash=NameHash(name);
|
||||||
entry.addr=addr;
|
entry.addr=addr;
|
||||||
entry.codeaddr=code_idx;
|
entry.codeaddr=code_idx;
|
||||||
entry.vclass=(char)vclass;
|
entry.vclass=(char)vclass;
|
||||||
@ -2780,8 +2781,7 @@ SC_FUNC symbol *addsym(const char *name,cell addr,int ident,int vclass,int tag,i
|
|||||||
/* then insert it in the list */
|
/* then insert it in the list */
|
||||||
if (vclass==sGLOBAL)
|
if (vclass==sGLOBAL)
|
||||||
return add_symbol(&glbtab,&entry,TRUE);
|
return add_symbol(&glbtab,&entry,TRUE);
|
||||||
else
|
return add_symbol(&loctab,&entry,FALSE);
|
||||||
return add_symbol(&loctab,&entry,FALSE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SC_FUNC symbol *addvariable(const char *name,cell addr,int ident,int vclass,int tag,
|
SC_FUNC symbol *addvariable(const char *name,cell addr,int ident,int vclass,int tag,
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h> /* for _MAX_PATH */
|
#include <stdlib.h> /* for _MAX_PATH */
|
||||||
#include "sc.h"
|
#include "sc.h"
|
||||||
|
#include "sp_symhash.h"
|
||||||
|
|
||||||
/* global variables
|
/* global variables
|
||||||
*
|
*
|
||||||
@ -100,6 +101,8 @@ SC_VDEFINE FILE *outf = NULL; /* (intermediate) text file written to */
|
|||||||
|
|
||||||
SC_VDEFINE jmp_buf errbuf;
|
SC_VDEFINE jmp_buf errbuf;
|
||||||
|
|
||||||
|
SC_VDEFINE HashTable *sp_Globals = NULL;
|
||||||
|
|
||||||
#if !defined SC_LIGHT
|
#if !defined SC_LIGHT
|
||||||
SC_VDEFINE int sc_makereport=FALSE; /* generate a cross-reference report */
|
SC_VDEFINE int sc_makereport=FALSE; /* generate a cross-reference report */
|
||||||
#endif
|
#endif
|
||||||
|
229
sourcepawn/compiler/sp_symhash.c
Normal file
229
sourcepawn/compiler/sp_symhash.c
Normal file
@ -0,0 +1,229 @@
|
|||||||
|
/* vim: set ts=4 sw=4 tw=99 et: */
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include "sc.h"
|
||||||
|
#include "sp_symhash.h"
|
||||||
|
|
||||||
|
SC_FUNC uint32_t
|
||||||
|
NameHash(const char *str)
|
||||||
|
{
|
||||||
|
size_t len = strlen(str);
|
||||||
|
const uint8_t *data = (uint8_t *)str;
|
||||||
|
#undef get16bits
|
||||||
|
#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \
|
||||||
|
|| defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__)
|
||||||
|
#define get16bits(d) (*((const uint16_t *) (d)))
|
||||||
|
#endif
|
||||||
|
#if !defined (get16bits)
|
||||||
|
#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8)\
|
||||||
|
+(uint32_t)(((const uint8_t *)(d))[0]) )
|
||||||
|
#endif
|
||||||
|
uint32_t hash = len, tmp;
|
||||||
|
int rem;
|
||||||
|
|
||||||
|
if (len <= 0 || data == NULL) return 0;
|
||||||
|
|
||||||
|
rem = len & 3;
|
||||||
|
len >>= 2;
|
||||||
|
|
||||||
|
/* Main loop */
|
||||||
|
for (;len > 0; len--) {
|
||||||
|
hash += get16bits (data);
|
||||||
|
tmp = (get16bits (data+2) << 11) ^ hash;
|
||||||
|
hash = (hash << 16) ^ tmp;
|
||||||
|
data += 2*sizeof (uint16_t);
|
||||||
|
hash += hash >> 11;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Handle end cases */
|
||||||
|
switch (rem) {
|
||||||
|
case 3: hash += get16bits (data);
|
||||||
|
hash ^= hash << 16;
|
||||||
|
hash ^= data[sizeof (uint16_t)] << 18;
|
||||||
|
hash += hash >> 11;
|
||||||
|
break;
|
||||||
|
case 2: hash += get16bits (data);
|
||||||
|
hash ^= hash << 11;
|
||||||
|
hash += hash >> 17;
|
||||||
|
break;
|
||||||
|
case 1: hash += *data;
|
||||||
|
hash ^= hash << 10;
|
||||||
|
hash += hash >> 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Force "avalanching" of final 127 bits */
|
||||||
|
hash ^= hash << 3;
|
||||||
|
hash += hash >> 5;
|
||||||
|
hash ^= hash << 4;
|
||||||
|
hash += hash >> 17;
|
||||||
|
hash ^= hash << 25;
|
||||||
|
hash += hash >> 6;
|
||||||
|
|
||||||
|
return hash;
|
||||||
|
|
||||||
|
#undef get16bits
|
||||||
|
}
|
||||||
|
|
||||||
|
SC_FUNC HashTable *NewHashTable()
|
||||||
|
{
|
||||||
|
HashTable *ht = (HashTable*)malloc(sizeof(HashTable));
|
||||||
|
if (!ht)
|
||||||
|
return ht;
|
||||||
|
ht->buckets = (HashEntry **)calloc(32, sizeof(HashEntry *));
|
||||||
|
if (!ht->buckets) {
|
||||||
|
free(ht);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
ht->nbuckets = 32;
|
||||||
|
ht->nused = 0;
|
||||||
|
ht->bucketmask = 32 - 1;
|
||||||
|
return ht;
|
||||||
|
}
|
||||||
|
|
||||||
|
SC_FUNC void
|
||||||
|
DestroyHashTable(HashTable *ht)
|
||||||
|
{
|
||||||
|
uint32_t i;
|
||||||
|
if (!ht)
|
||||||
|
return;
|
||||||
|
for (i = 0; i < ht->nbuckets; i++) {
|
||||||
|
HashEntry *he = ht->buckets[i];
|
||||||
|
while (he != NULL) {
|
||||||
|
HashEntry *next = he->next;
|
||||||
|
free(he);
|
||||||
|
he = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(ht->buckets);
|
||||||
|
free(ht);
|
||||||
|
}
|
||||||
|
|
||||||
|
SC_FUNC symbol *
|
||||||
|
FindTaggedInHashTable(HashTable *ht, const char *name, int fnumber,
|
||||||
|
int *cmptag)
|
||||||
|
{
|
||||||
|
int count=0;
|
||||||
|
symbol *firstmatch=NULL;
|
||||||
|
uint32_t hash = NameHash(name);
|
||||||
|
uint32_t bucket = hash & ht->bucketmask;
|
||||||
|
HashEntry *he = ht->buckets[bucket];
|
||||||
|
|
||||||
|
assert(cmptag!=NULL);
|
||||||
|
|
||||||
|
while (he != NULL) {
|
||||||
|
symbol *sym = he->sym;
|
||||||
|
if ((sym->parent==NULL || sym->ident==iCONSTEXPR) &&
|
||||||
|
(sym->fnumber<0 || sym->fnumber==fnumber) &&
|
||||||
|
(strcmp(sym->name, name) == 0))
|
||||||
|
{
|
||||||
|
/* return closest match or first match; count number of matches */
|
||||||
|
if (firstmatch==NULL)
|
||||||
|
firstmatch=sym;
|
||||||
|
if (*cmptag==0)
|
||||||
|
count++;
|
||||||
|
if (*cmptag==sym->tag) {
|
||||||
|
*cmptag=1; /* good match found, set number of matches to 1 */
|
||||||
|
return sym;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
he = he->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (firstmatch!=NULL)
|
||||||
|
*cmptag=count;
|
||||||
|
return firstmatch;
|
||||||
|
}
|
||||||
|
|
||||||
|
SC_FUNC symbol *
|
||||||
|
FindInHashTable(HashTable *ht, const char *name, int fnumber)
|
||||||
|
{
|
||||||
|
uint32_t hash = NameHash(name);
|
||||||
|
uint32_t bucket = hash & ht->bucketmask;
|
||||||
|
HashEntry *he = ht->buckets[bucket];
|
||||||
|
|
||||||
|
while (he != NULL) {
|
||||||
|
symbol *sym = he->sym;
|
||||||
|
if ((sym->parent==NULL || sym->ident==iCONSTEXPR) &&
|
||||||
|
(sym->fnumber<0 || sym->fnumber==fnumber) &&
|
||||||
|
(strcmp(sym->name, name) == 0))
|
||||||
|
{
|
||||||
|
return sym;
|
||||||
|
}
|
||||||
|
he = he->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ResizeHashTable(HashTable *ht)
|
||||||
|
{
|
||||||
|
uint32_t i;
|
||||||
|
uint32_t xnbuckets = ht->nbuckets * 2;
|
||||||
|
uint32_t xbucketmask = xnbuckets - 1;
|
||||||
|
HashEntry **xbuckets = (HashEntry **)calloc(xnbuckets, sizeof(HashEntry*));
|
||||||
|
if (!xbuckets)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (i = 0; i < ht->nbuckets; i++) {
|
||||||
|
HashEntry *he = ht->buckets[i];
|
||||||
|
while (he != NULL) {
|
||||||
|
HashEntry *next = he->next;
|
||||||
|
uint32_t bucket = he->sym->hash & xbucketmask;
|
||||||
|
he->next = xbuckets[bucket];
|
||||||
|
xbuckets[bucket] = he;
|
||||||
|
he = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(ht->buckets);
|
||||||
|
ht->buckets = xbuckets;
|
||||||
|
ht->nbuckets = xnbuckets;
|
||||||
|
ht->bucketmask = xbucketmask;
|
||||||
|
}
|
||||||
|
|
||||||
|
SC_FUNC void
|
||||||
|
AddToHashTable(HashTable *ht, symbol *sym)
|
||||||
|
{
|
||||||
|
uint32_t bucket = sym->hash & ht->bucketmask;
|
||||||
|
HashEntry **hep;
|
||||||
|
|
||||||
|
hep = &ht->buckets[bucket];
|
||||||
|
while (*hep) {
|
||||||
|
assert((*hep)->sym != sym);
|
||||||
|
hep = &(*hep)->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
HashEntry *he = (HashEntry *)malloc(sizeof(HashEntry));
|
||||||
|
if (!he)
|
||||||
|
error(123);
|
||||||
|
he->sym = sym;
|
||||||
|
he->next = NULL;
|
||||||
|
*hep = he;
|
||||||
|
ht->nused++;
|
||||||
|
|
||||||
|
if (ht->nused > ht->nbuckets && ht->nbuckets <= INT_MAX / 2)
|
||||||
|
ResizeHashTable(ht);
|
||||||
|
}
|
||||||
|
|
||||||
|
SC_FUNC void
|
||||||
|
RemoveFromHashTable(HashTable *ht, symbol *sym)
|
||||||
|
{
|
||||||
|
uint32_t bucket = sym->hash & ht->bucketmask;
|
||||||
|
HashEntry **hep = &ht->buckets[bucket];
|
||||||
|
HashEntry *he = *hep;
|
||||||
|
|
||||||
|
while (he != NULL) {
|
||||||
|
if (he->sym == sym) {
|
||||||
|
*hep = he->next;
|
||||||
|
free(he);
|
||||||
|
ht->nused--;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
hep = &he->next;
|
||||||
|
he = *hep;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
|
28
sourcepawn/compiler/sp_symhash.h
Normal file
28
sourcepawn/compiler/sp_symhash.h
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
/* vim: set ts=4 sw=4 tw=99 et: */
|
||||||
|
#ifndef _INCLUDE_SPCOMP_SYMHASH_H_
|
||||||
|
#define _INCLUDE_SPCOMP_SYMHASH_H_
|
||||||
|
|
||||||
|
SC_FUNC uint32_t NameHash(const char *str);
|
||||||
|
|
||||||
|
typedef struct HashEntry {
|
||||||
|
symbol *sym;
|
||||||
|
struct HashEntry *next;
|
||||||
|
} HashEntry;
|
||||||
|
|
||||||
|
struct HashTable {
|
||||||
|
uint32_t nbuckets;
|
||||||
|
uint32_t nused;
|
||||||
|
uint32_t bucketmask;
|
||||||
|
HashEntry **buckets;
|
||||||
|
};
|
||||||
|
|
||||||
|
SC_FUNC HashTable *NewHashTable();
|
||||||
|
SC_FUNC void DestroyHashTable(HashTable *ht);
|
||||||
|
SC_FUNC void AddToHashTable(HashTable *ht, symbol *sym);
|
||||||
|
SC_FUNC void RemoveFromHashTable(HashTable *ht, symbol *sym);
|
||||||
|
SC_FUNC symbol *FindInHashTable(HashTable *ht, const char *name, int fnumber);
|
||||||
|
SC_FUNC symbol *FindTaggedInHashTable(HashTable *ht, const char *name, int fnumber,
|
||||||
|
int *cmptag);
|
||||||
|
|
||||||
|
#endif /* _INCLUDE_SPCOMP_SYMHASH_H_ */
|
||||||
|
|
Loading…
Reference in New Issue
Block a user