Team Ai
Modelpublic

AryaWu/sqlite

sourceHugging Faceupdated 10mo agoView on Hugging Face
0likes
hash.c274 linesDownload Raw Back to src
1/*2** 2001 September 223**4** The author disclaims copyright to this source code.  In place of5** a legal notice, here is a blessing:6**7**    May you do good and not evil.8**    May you find forgiveness for yourself and forgive others.9**    May you share freely, never taking more than you give.10**11*************************************************************************12** This is the implementation of generic hash-tables13** used in SQLite.14*/15#include "sqliteInt.h"16#include <assert.h>17 18/* Turn bulk memory into a hash table object by initializing the19** fields of the Hash structure.20**21** "pNew" is a pointer to the hash table that is to be initialized.22*/23void sqlite3HashInit(Hash *pNew){24  assert( pNew!=0 );25  pNew->first = 0;26  pNew->count = 0;27  pNew->htsize = 0;28  pNew->ht = 0;29}30 31/* Remove all entries from a hash table.  Reclaim all memory.32** Call this routine to delete a hash table or to reset a hash table33** to the empty state.34*/35void sqlite3HashClear(Hash *pH){36  HashElem *elem;         /* For looping over all elements of the table */37 38  assert( pH!=0 );39  elem = pH->first;40  pH->first = 0;41  sqlite3_free(pH->ht);42  pH->ht = 0;43  pH->htsize = 0;44  while( elem ){45    HashElem *next_elem = elem->next;46    sqlite3_free(elem);47    elem = next_elem;48  }49  pH->count = 0;50}51 52/*53** The hashing function.54*/55static unsigned int strHash(const char *z){56  unsigned int h = 0;57  while( z[0] ){     /*OPTIMIZATION-IF-TRUE*/58    /* Knuth multiplicative hashing.  (Sorting & Searching, p. 510).59    ** 0x9e3779b1 is 2654435761 which is the closest prime number to60    ** (2**32)*golden_ratio, where golden_ratio = (sqrt(5) - 1)/2.61    **62    ** Only bits 0xdf for ASCII and bits 0xbf for EBCDIC each octet are63    ** hashed since the omitted bits determine the upper/lower case difference.64    */65#ifdef SQLITE_EBCDIC66    h += 0xbf & (unsigned char)*(z++);67#else68    h += 0xdf & (unsigned char)*(z++);69#endif70    h *= 0x9e3779b1;71  }72  return h;73}74 75 76/* Link pNew element into the hash table pH.  If pEntry!=0 then also77** insert pNew into the pEntry hash bucket.78*/79static void insertElement(80  Hash *pH,              /* The complete hash table */81  struct _ht *pEntry,    /* The entry into which pNew is inserted */82  HashElem *pNew         /* The element to be inserted */83){84  HashElem *pHead;       /* First element already in pEntry */85  if( pEntry ){86    pHead = pEntry->count ? pEntry->chain : 0;87    pEntry->count++;88    pEntry->chain = pNew;89  }else{90    pHead = 0;91  }92  if( pHead ){93    pNew->next = pHead;94    pNew->prev = pHead->prev;95    if( pHead->prev ){ pHead->prev->next = pNew; }96    else             { pH->first = pNew; }97    pHead->prev = pNew;98  }else{99    pNew->next = pH->first;100    if( pH->first ){ pH->first->prev = pNew; }101    pNew->prev = 0;102    pH->first = pNew;103  }104}105 106 107/* Resize the hash table so that it contains "new_size" buckets.108**109** The hash table might fail to resize if sqlite3_malloc() fails or110** if the new size is the same as the prior size.111** Return TRUE if the resize occurs and false if not.112*/113static int rehash(Hash *pH, unsigned int new_size){114  struct _ht *new_ht;            /* The new hash table */115  HashElem *elem, *next_elem;    /* For looping over existing elements */116 117#if SQLITE_MALLOC_SOFT_LIMIT>0118  if( new_size*sizeof(struct _ht)>SQLITE_MALLOC_SOFT_LIMIT ){119    new_size = SQLITE_MALLOC_SOFT_LIMIT/sizeof(struct _ht);120  }121  if( new_size==pH->htsize ) return 0;122#endif123 124  /* The inability to allocates space for a larger hash table is125  ** a performance hit but it is not a fatal error.  So mark the126  ** allocation as a benign. Use sqlite3Malloc()/memset(0) instead of 127  ** sqlite3MallocZero() to make the allocation, as sqlite3MallocZero()128  ** only zeroes the requested number of bytes whereas this module will129  ** use the actual amount of space allocated for the hash table (which130  ** may be larger than the requested amount).131  */132  sqlite3BeginBenignMalloc();133  new_ht = (struct _ht *)sqlite3Malloc( new_size*sizeof(struct _ht) );134  sqlite3EndBenignMalloc();135 136  if( new_ht==0 ) return 0;137  sqlite3_free(pH->ht);138  pH->ht = new_ht;139  pH->htsize = new_size = sqlite3MallocSize(new_ht)/sizeof(struct _ht);140  memset(new_ht, 0, new_size*sizeof(struct _ht));141  for(elem=pH->first, pH->first=0; elem; elem = next_elem){142    next_elem = elem->next;143    insertElement(pH, &new_ht[elem->h % new_size], elem);144  }145  return 1;146}147 148/* This function (for internal use only) locates an element in an149** hash table that matches the given key.  If no element is found,150** a pointer to a static null element with HashElem.data==0 is returned.151** If pH is not NULL, then the hash for this key is written to *pH.152*/153static HashElem *findElementWithHash(154  const Hash *pH,     /* The pH to be searched */155  const char *pKey,   /* The key we are searching for */156  unsigned int *pHash /* Write the hash value here */157){158  HashElem *elem;                /* Used to loop thru the element list */159  unsigned int count;            /* Number of elements left to test */160  unsigned int h;                /* The computed hash */161  static HashElem nullElement = { 0, 0, 0, 0, 0 };162 163  h = strHash(pKey);164  if( pH->ht ){   /*OPTIMIZATION-IF-TRUE*/165    struct _ht *pEntry;166    pEntry = &pH->ht[h % pH->htsize];167    elem = pEntry->chain;168    count = pEntry->count;169  }else{170    elem = pH->first;171    count = pH->count;172  }173  if( pHash ) *pHash = h;174  while( count ){175    assert( elem!=0 );176    if( h==elem->h && sqlite3StrICmp(elem->pKey,pKey)==0 ){ 177      return elem;178    }179    elem = elem->next;180    count--;181  }182  return &nullElement;183}184 185/* Remove a single entry from the hash table given a pointer to that186** element and a hash on the element's key.187*/188static void removeElement(189  Hash *pH,         /* The pH containing "elem" */190  HashElem *elem    /* The element to be removed from the pH */191){192  struct _ht *pEntry;193  if( elem->prev ){194    elem->prev->next = elem->next; 195  }else{196    pH->first = elem->next;197  }198  if( elem->next ){199    elem->next->prev = elem->prev;200  }201  if( pH->ht ){202    pEntry = &pH->ht[elem->h % pH->htsize];203    if( pEntry->chain==elem ){204      pEntry->chain = elem->next;205    }206    assert( pEntry->count>0 );207    pEntry->count--;208  }209  sqlite3_free( elem );210  pH->count--;211  if( pH->count==0 ){212    assert( pH->first==0 );213    assert( pH->count==0 );214    sqlite3HashClear(pH);215  }216}217 218/* Attempt to locate an element of the hash table pH with a key219** that matches pKey.  Return the data for this element if it is220** found, or NULL if there is no match.221*/222void *sqlite3HashFind(const Hash *pH, const char *pKey){223  assert( pH!=0 );224  assert( pKey!=0 );225  return findElementWithHash(pH, pKey, 0)->data;226}227 228/* Insert an element into the hash table pH.  The key is pKey229** and the data is "data".230**231** If no element exists with a matching key, then a new232** element is created and NULL is returned.233**234** If another element already exists with the same key, then the235** new data replaces the old data and the old data is returned.236** The key is not copied in this instance.  If a malloc fails, then237** the new data is returned and the hash table is unchanged.238**239** If the "data" parameter to this function is NULL, then the240** element corresponding to "key" is removed from the hash table.241*/242void *sqlite3HashInsert(Hash *pH, const char *pKey, void *data){243  unsigned int h;       /* the hash of the key modulo hash table size */244  HashElem *elem;       /* Used to loop thru the element list */245  HashElem *new_elem;   /* New element added to the pH */246 247  assert( pH!=0 );248  assert( pKey!=0 );249  elem = findElementWithHash(pH,pKey,&h);250  if( elem->data ){251    void *old_data = elem->data;252    if( data==0 ){253      removeElement(pH,elem);254    }else{255      elem->data = data;256      elem->pKey = pKey;257    }258    return old_data;259  }260  if( data==0 ) return 0;261  new_elem = (HashElem*)sqlite3Malloc( sizeof(HashElem) );262  if( new_elem==0 ) return data;263  new_elem->pKey = pKey;264  new_elem->h = h;265  new_elem->data = data;266  pH->count++;267  if( pH->count>=5 && pH->count > 2*pH->htsize ){268    rehash(pH, pH->count*3);269  }270  insertElement(pH, pH->ht ? &pH->ht[new_elem->h % pH->htsize] : 0, new_elem);271  return 0;272}273 274