Port sp_symhash to C++.
This commit is contained in:
		
							parent
							
								
									f5efdbf6f5
								
							
						
					
					
						commit
						5a4c50ce55
					
				@ -42,6 +42,7 @@ binary = SM.Program(builder, 'spcomp')
 | 
				
			|||||||
compiler = binary.compiler
 | 
					compiler = binary.compiler
 | 
				
			||||||
compiler.includes += [
 | 
					compiler.includes += [
 | 
				
			||||||
  os.path.join(builder.sourcePath, 'public'),
 | 
					  os.path.join(builder.sourcePath, 'public'),
 | 
				
			||||||
 | 
					  os.path.join(builder.sourcePath, 'public', 'amtl'),
 | 
				
			||||||
  os.path.join(builder.sourcePath, 'public', 'sourcepawn'),
 | 
					  os.path.join(builder.sourcePath, 'public', 'sourcepawn'),
 | 
				
			||||||
  os.path.join(builder.sourcePath, 'sourcepawn', 'compiler'),
 | 
					  os.path.join(builder.sourcePath, 'sourcepawn', 'compiler'),
 | 
				
			||||||
  os.path.join(builder.buildPath, 'includes'),
 | 
					  os.path.join(builder.buildPath, 'includes'),
 | 
				
			||||||
@ -50,7 +51,8 @@ compiler.includes += [
 | 
				
			|||||||
compiler.sourcedeps += packed_includes
 | 
					compiler.sourcedeps += packed_includes
 | 
				
			||||||
 
 | 
					 
 | 
				
			||||||
if compiler.cc.behavior == 'gcc':
 | 
					if compiler.cc.behavior == 'gcc':
 | 
				
			||||||
  compiler.cflags += ['-std=c99', '-Wno-format']
 | 
					  compiler.cflags += ['-Wno-format']
 | 
				
			||||||
 | 
					  compiler.c_only_flags += ['-std=c99']
 | 
				
			||||||
  if builder.target_platform == 'linux':
 | 
					  if builder.target_platform == 'linux':
 | 
				
			||||||
    compiler.postlink += ['-lgcc', '-lm']
 | 
					    compiler.postlink += ['-lgcc', '-lm']
 | 
				
			||||||
elif compiler.cc.behavior == 'msvc':
 | 
					elif compiler.cc.behavior == 'msvc':
 | 
				
			||||||
@ -107,7 +109,7 @@ binary.sources += [
 | 
				
			|||||||
  'zlib/trees.c',
 | 
					  'zlib/trees.c',
 | 
				
			||||||
  'zlib/uncompr.c',
 | 
					  'zlib/uncompr.c',
 | 
				
			||||||
  'zlib/zutil.c',
 | 
					  'zlib/zutil.c',
 | 
				
			||||||
  'sp_symhash.c'
 | 
					  'sp_symhash.cpp'
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
if builder.target_platform != 'windows':
 | 
					if builder.target_platform != 'windows':
 | 
				
			||||||
  binary.sources.append('binreloc.c')
 | 
					  binary.sources.append('binreloc.c')
 | 
				
			||||||
 | 
				
			|||||||
@ -599,7 +599,11 @@ long pc_lengthbin(void *handle); /* return the length of the file */
 | 
				
			|||||||
 * files are "external"
 | 
					 * files are "external"
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
#if !defined SC_FUNC
 | 
					#if !defined SC_FUNC
 | 
				
			||||||
  #define SC_FUNC
 | 
					# if defined(__cplusplus)
 | 
				
			||||||
 | 
					#  define SC_FUNC extern "C"
 | 
				
			||||||
 | 
					# else
 | 
				
			||||||
 | 
					#  define SC_FUNC
 | 
				
			||||||
 | 
					# endif
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
#if !defined SC_VDECL
 | 
					#if !defined SC_VDECL
 | 
				
			||||||
  #define SC_VDECL  extern
 | 
					  #define SC_VDECL  extern
 | 
				
			||||||
@ -616,7 +620,7 @@ SC_FUNC void set_extension(char *filename,char *extension,int force);
 | 
				
			|||||||
SC_FUNC symbol *fetchfunc(char *name);
 | 
					SC_FUNC symbol *fetchfunc(char *name);
 | 
				
			||||||
SC_FUNC char *operator_symname(char *symname,char *opername,int tag1,int tag2,int numtags,int resulttag);
 | 
					SC_FUNC char *operator_symname(char *symname,char *opername,int tag1,int tag2,int numtags,int resulttag);
 | 
				
			||||||
SC_FUNC char *funcdisplayname(char *dest,char *funcname);
 | 
					SC_FUNC char *funcdisplayname(char *dest,char *funcname);
 | 
				
			||||||
SC_FUNC int constexpr(cell *val,int *tag,symbol **symptr);
 | 
					SC_FUNC int exprconst(cell *val,int *tag,symbol **symptr);
 | 
				
			||||||
SC_FUNC constvalue *append_constval(constvalue *table,const char *name,cell val,int index);
 | 
					SC_FUNC constvalue *append_constval(constvalue *table,const char *name,cell val,int index);
 | 
				
			||||||
SC_FUNC constvalue *find_constval(constvalue *table,char *name,int index);
 | 
					SC_FUNC constvalue *find_constval(constvalue *table,char *name,int index);
 | 
				
			||||||
SC_FUNC void delete_consttable(constvalue *table);
 | 
					SC_FUNC void delete_consttable(constvalue *table);
 | 
				
			||||||
 | 
				
			|||||||
@ -2794,7 +2794,7 @@ static cell init(int ident,int *tag,int *errorfound)
 | 
				
			|||||||
      litidx=1;         /* reset literal queue */
 | 
					      litidx=1;         /* reset literal queue */
 | 
				
			||||||
    } /* if */
 | 
					    } /* if */
 | 
				
			||||||
    *tag=pc_tag_string;
 | 
					    *tag=pc_tag_string;
 | 
				
			||||||
  } else if (constexpr(&i,tag,NULL)){
 | 
					  } else if (exprconst(&i,tag,NULL)){
 | 
				
			||||||
    litadd(i);          /* store expression result in literal table */
 | 
					    litadd(i);          /* store expression result in literal table */
 | 
				
			||||||
  } else {
 | 
					  } else {
 | 
				
			||||||
    if (errorfound!=NULL)
 | 
					    if (errorfound!=NULL)
 | 
				
			||||||
@ -2819,7 +2819,7 @@ static cell needsub(int *tag,constvalue **enumroot)
 | 
				
			|||||||
  if (matchtoken(']'))      /* we have already seen "[" */
 | 
					  if (matchtoken(']'))      /* we have already seen "[" */
 | 
				
			||||||
    return 0;               /* zero size (like "char msg[]") */
 | 
					    return 0;               /* zero size (like "char msg[]") */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  constexpr(&val,tag,&sym); /* get value (must be constant expression) */
 | 
					  exprconst(&val,tag,&sym); /* get value (must be constant expression) */
 | 
				
			||||||
  if (val<0) {
 | 
					  if (val<0) {
 | 
				
			||||||
    error(9);               /* negative array size is invalid; assumed zero */
 | 
					    error(9);               /* negative array size is invalid; assumed zero */
 | 
				
			||||||
    val=0;
 | 
					    val=0;
 | 
				
			||||||
@ -2891,7 +2891,7 @@ static void decl_const(int vclass)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    symbolline=fline;                   /* save line where symbol was found */
 | 
					    symbolline=fline;                   /* save line where symbol was found */
 | 
				
			||||||
    needtoken('=');
 | 
					    needtoken('=');
 | 
				
			||||||
    constexpr(&val,&exprtag,NULL);      /* get value */
 | 
					    exprconst(&val,&exprtag,NULL);      /* get value */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* add_constant() checks for duplicate definitions */
 | 
					    /* add_constant() checks for duplicate definitions */
 | 
				
			||||||
    /* temporarily reset the line number to where the symbol was defined */
 | 
					    /* temporarily reset the line number to where the symbol was defined */
 | 
				
			||||||
@ -4523,11 +4523,11 @@ static void decl_enum(int vclass)
 | 
				
			|||||||
  multiplier=1;
 | 
					  multiplier=1;
 | 
				
			||||||
  if (matchtoken('(')) {
 | 
					  if (matchtoken('(')) {
 | 
				
			||||||
    if (matchtoken(taADD)) {
 | 
					    if (matchtoken(taADD)) {
 | 
				
			||||||
      constexpr(&increment,NULL,NULL);
 | 
					      exprconst(&increment,NULL,NULL);
 | 
				
			||||||
    } else if (matchtoken(taMULT)) {
 | 
					    } else if (matchtoken(taMULT)) {
 | 
				
			||||||
      constexpr(&multiplier,NULL,NULL);
 | 
					      exprconst(&multiplier,NULL,NULL);
 | 
				
			||||||
    } else if (matchtoken(taSHL)) {
 | 
					    } else if (matchtoken(taSHL)) {
 | 
				
			||||||
      constexpr(&val,NULL,NULL);
 | 
					      exprconst(&val,NULL,NULL);
 | 
				
			||||||
      while (val-->0)
 | 
					      while (val-->0)
 | 
				
			||||||
        multiplier*=2;
 | 
					        multiplier*=2;
 | 
				
			||||||
    } /* if */
 | 
					    } /* if */
 | 
				
			||||||
@ -4568,12 +4568,12 @@ static void decl_enum(int vclass)
 | 
				
			|||||||
    size=increment;                     /* default increment of 'val' */
 | 
					    size=increment;                     /* default increment of 'val' */
 | 
				
			||||||
    fieldtag=0;                         /* default field tag */
 | 
					    fieldtag=0;                         /* default field tag */
 | 
				
			||||||
    if (matchtoken('[')) {
 | 
					    if (matchtoken('[')) {
 | 
				
			||||||
      constexpr(&size,&fieldtag,NULL);  /* get size */
 | 
					      exprconst(&size,&fieldtag,NULL);  /* get size */
 | 
				
			||||||
      needtoken(']');
 | 
					      needtoken(']');
 | 
				
			||||||
    } /* if */
 | 
					    } /* if */
 | 
				
			||||||
    /* :TODO: do we need a size modifier here for pc_tag_string? */
 | 
					    /* :TODO: do we need a size modifier here for pc_tag_string? */
 | 
				
			||||||
    if (matchtoken('='))
 | 
					    if (matchtoken('='))
 | 
				
			||||||
      constexpr(&value,NULL,NULL);      /* get value */
 | 
					      exprconst(&value,NULL,NULL);      /* get value */
 | 
				
			||||||
    /* add_constant() checks whether a variable (global or local) or
 | 
					    /* add_constant() checks whether a variable (global or local) or
 | 
				
			||||||
     * a constant with the same name already exists
 | 
					     * a constant with the same name already exists
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
@ -5125,7 +5125,7 @@ static symbol *funcstub(int tokid, declinfo_t *decl, const int *thistag)
 | 
				
			|||||||
        tokeninfo(&val,&str);
 | 
					        tokeninfo(&val,&str);
 | 
				
			||||||
        insert_alias(sym->name,str);
 | 
					        insert_alias(sym->name,str);
 | 
				
			||||||
      } else {
 | 
					      } else {
 | 
				
			||||||
        constexpr(&val,NULL,NULL);
 | 
					        exprconst(&val,NULL,NULL);
 | 
				
			||||||
        sym->addr=val;
 | 
					        sym->addr=val;
 | 
				
			||||||
        /* At the moment, I have assumed that this syntax is only valid if
 | 
					        /* At the moment, I have assumed that this syntax is only valid if
 | 
				
			||||||
         * val < 0. To properly mix "normal" native functions and indexed
 | 
					         * val < 0. To properly mix "normal" native functions and indexed
 | 
				
			||||||
@ -5728,7 +5728,7 @@ static void doarg(declinfo_t *decl, int offset, int fpublic, int chkshadow, argi
 | 
				
			|||||||
        while (paranthese--)
 | 
					        while (paranthese--)
 | 
				
			||||||
          needtoken(')');
 | 
					          needtoken(')');
 | 
				
			||||||
      } else {
 | 
					      } else {
 | 
				
			||||||
        constexpr(&arg->defvalue.val,&arg->defvalue_tag,NULL);
 | 
					        exprconst(&arg->defvalue.val,&arg->defvalue_tag,NULL);
 | 
				
			||||||
        assert(type->numtags > 0);
 | 
					        assert(type->numtags > 0);
 | 
				
			||||||
        matchtag(type->tags[0], arg->defvalue_tag, TRUE);
 | 
					        matchtag(type->tags[0], arg->defvalue_tag, TRUE);
 | 
				
			||||||
      } /* if */
 | 
					      } /* if */
 | 
				
			||||||
@ -6901,9 +6901,9 @@ static int doexpr2(int comma,int chkeffect,int allowarray,int mark_endexpr,
 | 
				
			|||||||
  return ident;
 | 
					  return ident;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*  constexpr
 | 
					/*  exprconst
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
SC_FUNC int constexpr(cell *val,int *tag,symbol **symptr)
 | 
					SC_FUNC int exprconst(cell *val,int *tag,symbol **symptr)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  int ident,index;
 | 
					  int ident,index;
 | 
				
			||||||
  cell cidx;
 | 
					  cell cidx;
 | 
				
			||||||
@ -7294,7 +7294,7 @@ static void doswitch(void)
 | 
				
			|||||||
         *     parse all expressions until that special token.
 | 
					         *     parse all expressions until that special token.
 | 
				
			||||||
         */
 | 
					         */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        constexpr(&val,NULL,NULL);
 | 
					        exprconst(&val,NULL,NULL);
 | 
				
			||||||
        /* Search the insertion point (the table is kept in sorted order, so
 | 
					        /* Search the insertion point (the table is kept in sorted order, so
 | 
				
			||||||
         * that advanced abstract machines can sift the case table with a
 | 
					         * that advanced abstract machines can sift the case table with a
 | 
				
			||||||
         * binary search). Check for duplicate case values at the same time.
 | 
					         * binary search). Check for duplicate case values at the same time.
 | 
				
			||||||
 | 
				
			|||||||
@ -796,7 +796,7 @@ static int preproc_expr(cell *val,int *tag)
 | 
				
			|||||||
  term=strchr((char*)pline,'\0');
 | 
					  term=strchr((char*)pline,'\0');
 | 
				
			||||||
  assert(term!=NULL);
 | 
					  assert(term!=NULL);
 | 
				
			||||||
  chrcat((char*)pline,PREPROC_TERM);    /* the "DEL" code (see SC.H) */
 | 
					  chrcat((char*)pline,PREPROC_TERM);    /* the "DEL" code (see SC.H) */
 | 
				
			||||||
  result=constexpr(val,tag,NULL);       /* get value (or 0 on error) */
 | 
					  result=exprconst(val,tag,NULL);       /* get value (or 0 on error) */
 | 
				
			||||||
  *term='\0';                           /* erase the token (if still present) */
 | 
					  *term='\0';                           /* erase the token (if still present) */
 | 
				
			||||||
  lexclr(FALSE);                        /* clear any "pushed" tokens */
 | 
					  lexclr(FALSE);                        /* clear any "pushed" tokens */
 | 
				
			||||||
  return result;
 | 
					  return result;
 | 
				
			||||||
 | 
				
			|||||||
@ -1,230 +0,0 @@
 | 
				
			|||||||
/* vim: set ts=4 sw=4 tw=99 et: */
 | 
					 | 
				
			||||||
#include <stdlib.h>
 | 
					 | 
				
			||||||
#include <string.h>
 | 
					 | 
				
			||||||
#include <assert.h>
 | 
					 | 
				
			||||||
#include "sp_file_headers.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, *he;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    hep = &ht->buckets[bucket];
 | 
					 | 
				
			||||||
    while (*hep) {
 | 
					 | 
				
			||||||
        assert((*hep)->sym != sym);
 | 
					 | 
				
			||||||
        hep = &(*hep)->next;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    he = (HashEntry *)malloc(sizeof(HashEntry));
 | 
					 | 
				
			||||||
    if (!he)
 | 
					 | 
				
			||||||
      error(163);
 | 
					 | 
				
			||||||
    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);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
							
								
								
									
										156
									
								
								sourcepawn/compiler/sp_symhash.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										156
									
								
								sourcepawn/compiler/sp_symhash.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,156 @@
 | 
				
			|||||||
 | 
					// vim: set ts=8 sts=2 sw=2 tw=99 et:
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <assert.h>
 | 
				
			||||||
 | 
					#include "sp_file_headers.h"
 | 
				
			||||||
 | 
					#include "sc.h"
 | 
				
			||||||
 | 
					#include "sp_symhash.h"
 | 
				
			||||||
 | 
					#include <am-hashtable.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct NameAndScope
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  const char *name;
 | 
				
			||||||
 | 
					  int fnumber;
 | 
				
			||||||
 | 
					  int *cmptag;
 | 
				
			||||||
 | 
					  mutable symbol *matched;
 | 
				
			||||||
 | 
					  mutable int count;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  NameAndScope(const char *name, int fnumber, int *cmptag)
 | 
				
			||||||
 | 
					   : name(name),
 | 
				
			||||||
 | 
					     fnumber(fnumber),
 | 
				
			||||||
 | 
					     cmptag(cmptag),
 | 
				
			||||||
 | 
					     matched(nullptr),
 | 
				
			||||||
 | 
					     count(0)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct SymbolHashPolicy
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  typedef symbol *Payload;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Everything with the same name has the same hash, because the compiler
 | 
				
			||||||
 | 
					  // wants to know two names that have the same tag for some reason. Even
 | 
				
			||||||
 | 
					  // so, we can't be that accurate, since we might match the right symbol
 | 
				
			||||||
 | 
					  // very early.
 | 
				
			||||||
 | 
					  static uint32_t hash(const NameAndScope &key) {
 | 
				
			||||||
 | 
					    return ke::HashCharSequence(key.name, strlen(key.name));
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  static uint32_t hash(const symbol *s) {
 | 
				
			||||||
 | 
					    return ke::HashCharSequence(s->name, strlen(s->name));
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  static bool matches(const NameAndScope &key, symbol *sym) {
 | 
				
			||||||
 | 
					    if (sym->parent && sym->ident != iCONSTEXPR)
 | 
				
			||||||
 | 
					      return false;
 | 
				
			||||||
 | 
					    if (sym->fnumber >= 0 && sym->fnumber != key.fnumber)
 | 
				
			||||||
 | 
					      return false;
 | 
				
			||||||
 | 
					    if (strcmp(key.name, sym->name) != 0)
 | 
				
			||||||
 | 
					      return false;
 | 
				
			||||||
 | 
					    if (key.cmptag) {
 | 
				
			||||||
 | 
					      key.count++;
 | 
				
			||||||
 | 
					      key.matched = sym;
 | 
				
			||||||
 | 
					      if (*key.cmptag != sym->tag)
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return true;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  static bool matches(const symbol *key, symbol *sym) {
 | 
				
			||||||
 | 
					    return key == sym;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct HashTable : public ke::HashTable<SymbolHashPolicy>
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SC_FUNC uint32_t
 | 
				
			||||||
 | 
					NameHash(const char *str)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  return ke::HashCharSequence(str, strlen(str));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SC_FUNC HashTable *NewHashTable()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  HashTable *ht = new HashTable();
 | 
				
			||||||
 | 
					  if (!ht->init()) {
 | 
				
			||||||
 | 
					    delete ht;
 | 
				
			||||||
 | 
					    return nullptr;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return ht;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SC_FUNC void
 | 
				
			||||||
 | 
					DestroyHashTable(HashTable *ht)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  delete ht;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SC_FUNC symbol *
 | 
				
			||||||
 | 
					FindTaggedInHashTable(HashTable *ht, const char *name, int fnumber, int *cmptag)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  NameAndScope nas(name, fnumber, cmptag);
 | 
				
			||||||
 | 
					  HashTable::Result r = ht->find(nas);
 | 
				
			||||||
 | 
					  if (!r.found()) {
 | 
				
			||||||
 | 
					    if (nas.matched) {
 | 
				
			||||||
 | 
					      *cmptag = nas.count;
 | 
				
			||||||
 | 
					      return nas.matched;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return nullptr;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  *cmptag = 1;
 | 
				
			||||||
 | 
					  return *r;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SC_FUNC symbol *
 | 
				
			||||||
 | 
					FindInHashTable(HashTable *ht, const char *name, int fnumber)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  NameAndScope nas(name, fnumber, nullptr);
 | 
				
			||||||
 | 
					  HashTable::Result r = ht->find(nas);
 | 
				
			||||||
 | 
					  if (!r.found())
 | 
				
			||||||
 | 
					    return nullptr;
 | 
				
			||||||
 | 
					  return *r;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SC_FUNC void
 | 
				
			||||||
 | 
					AddToHashTable(HashTable *ht, symbol *sym)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  HashTable::Insert i = ht->findForAdd(sym);
 | 
				
			||||||
 | 
					  assert(!i.found());
 | 
				
			||||||
 | 
					  ht->add(i, sym);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SC_FUNC void
 | 
				
			||||||
 | 
					RemoveFromHashTable(HashTable *ht, symbol *sym)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  HashTable::Result r = ht->find(sym);
 | 
				
			||||||
 | 
					  assert(r.found());
 | 
				
			||||||
 | 
					  ht->remove(r);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if defined __linux__ || defined __APPLE__
 | 
				
			||||||
 | 
					extern "C" void __cxa_pure_virtual(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void *operator new(size_t size)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return malloc(size);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void *operator new[](size_t size) 
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return malloc(size);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void operator delete(void *ptr) 
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						free(ptr);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void operator delete[](void * ptr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						free(ptr);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
@ -1,28 +1,18 @@
 | 
				
			|||||||
/* vim: set ts=4 sw=4 tw=99 et: */
 | 
					/* vim: set ts=4 sw=4 tw=99 et: */
 | 
				
			||||||
#ifndef _INCLUDE_SPCOMP_SYMHASH_H_
 | 
					#ifndef _INCLUDE_SPCOMP_SYMHASH_H_
 | 
				
			||||||
#define _INCLUDE_SPCOMP_SYMHASH_H_
 | 
					#define _INCLUDE_SPCOMP_SYMHASH_H_
 | 
				
			||||||
 | 
					
 | 
				
			||||||
SC_FUNC uint32_t NameHash(const char *str);
 | 
					SC_FUNC uint32_t NameHash(const char *str);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct HashEntry {
 | 
					struct HashTable;
 | 
				
			||||||
    symbol *sym;
 | 
					
 | 
				
			||||||
    struct HashEntry *next;
 | 
					SC_FUNC HashTable *NewHashTable();
 | 
				
			||||||
} HashEntry;
 | 
					SC_FUNC void DestroyHashTable(HashTable *ht);
 | 
				
			||||||
 | 
					SC_FUNC void AddToHashTable(HashTable *ht, symbol *sym);
 | 
				
			||||||
struct HashTable {
 | 
					SC_FUNC void RemoveFromHashTable(HashTable *ht, symbol *sym);
 | 
				
			||||||
    uint32_t nbuckets;
 | 
					SC_FUNC symbol *FindInHashTable(HashTable *ht, const char *name, int fnumber);
 | 
				
			||||||
    uint32_t nused;
 | 
					SC_FUNC symbol *FindTaggedInHashTable(HashTable *ht, const char *name, int fnumber,
 | 
				
			||||||
    uint32_t bucketmask;
 | 
					                                      int *cmptag);
 | 
				
			||||||
    HashEntry **buckets;
 | 
					
 | 
				
			||||||
};
 | 
					#endif /* _INCLUDE_SPCOMP_SYMHASH_H_ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
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