hash.c

Go to the documentation of this file.
00001 /*
00002 ** 2001 September 22
00003 **
00004 ** The author disclaims copyright to this source code.  In place of
00005 ** a legal notice, here is a blessing:
00006 **
00007 **    May you do good and not evil.
00008 **    May you find forgiveness for yourself and forgive others.
00009 **    May you share freely, never taking more than you give.
00010 **
00011 *************************************************************************
00012 ** This is the implementation of generic hash-tables
00013 ** used in SQLite.
00014 **
00015 ** $Id: hash.c,v 1.31 2008/10/10 17:41:29 drh Exp $
00016 */
00017 #include "sqliteInt.h"
00018 #include <assert.h>
00019 
00020 /* Turn bulk memory into a hash table object by initializing the
00021 ** fields of the Hash structure.
00022 **
00023 ** "pNew" is a pointer to the hash table that is to be initialized.
00024 ** "copyKey" is true if the hash table should make its own private
00025 ** copy of keys and false if it should just use the supplied pointer.
00026 */
00027 void sqlite3HashInit(Hash *pNew, int copyKey){
00028   assert( pNew!=0 );
00029   pNew->copyKey = copyKey!=0;
00030   pNew->first = 0;
00031   pNew->count = 0;
00032   pNew->htsize = 0;
00033   pNew->ht = 0;
00034 }
00035 
00036 /* Remove all entries from a hash table.  Reclaim all memory.
00037 ** Call this routine to delete a hash table or to reset a hash table
00038 ** to the empty state.
00039 */
00040 void sqlite3HashClear(Hash *pH){
00041   HashElem *elem;         /* For looping over all elements of the table */
00042 
00043   assert( pH!=0 );
00044   elem = pH->first;
00045   pH->first = 0;
00046   sqlite3_free(pH->ht);
00047   pH->ht = 0;
00048   pH->htsize = 0;
00049   while( elem ){
00050     HashElem *next_elem = elem->next;
00051     if( pH->copyKey && elem->pKey ){
00052       sqlite3_free(elem->pKey);
00053     }
00054     sqlite3_free(elem);
00055     elem = next_elem;
00056   }
00057   pH->count = 0;
00058 }
00059 
00060 /*
00061 ** Hash and comparison functions when the mode is SQLITE_HASH_STRING
00062 */
00063 static int strHash(const void *pKey, int nKey){
00064   const char *z = (const char *)pKey;
00065   int h = 0;
00066   if( nKey<=0 ) nKey = strlen(z);
00067   while( nKey > 0  ){
00068     h = (h<<3) ^ h ^ sqlite3UpperToLower[(unsigned char)*z++];
00069     nKey--;
00070   }
00071   return h & 0x7fffffff;
00072 }
00073 static int strCompare(const void *pKey1, int n1, const void *pKey2, int n2){
00074   if( n1!=n2 ) return 1;
00075   return sqlite3StrNICmp((const char*)pKey1,(const char*)pKey2,n1);
00076 }
00077 
00078 
00079 /* Link an element into the hash table
00080 */
00081 static void insertElement(
00082   Hash *pH,              /* The complete hash table */
00083   struct _ht *pEntry,    /* The entry into which pNew is inserted */
00084   HashElem *pNew         /* The element to be inserted */
00085 ){
00086   HashElem *pHead;       /* First element already in pEntry */
00087   pHead = pEntry->chain;
00088   if( pHead ){
00089     pNew->next = pHead;
00090     pNew->prev = pHead->prev;
00091     if( pHead->prev ){ pHead->prev->next = pNew; }
00092     else             { pH->first = pNew; }
00093     pHead->prev = pNew;
00094   }else{
00095     pNew->next = pH->first;
00096     if( pH->first ){ pH->first->prev = pNew; }
00097     pNew->prev = 0;
00098     pH->first = pNew;
00099   }
00100   pEntry->count++;
00101   pEntry->chain = pNew;
00102 }
00103 
00104 
00105 /* Resize the hash table so that it cantains "new_size" buckets.
00106 ** "new_size" must be a power of 2.  The hash table might fail 
00107 ** to resize if sqlite3_malloc() fails.
00108 */
00109 static void rehash(Hash *pH, int new_size){
00110   struct _ht *new_ht;            /* The new hash table */
00111   HashElem *elem, *next_elem;    /* For looping over existing elements */
00112 
00113 #ifdef SQLITE_MALLOC_SOFT_LIMIT
00114   if( new_size*sizeof(struct _ht)>SQLITE_MALLOC_SOFT_LIMIT ){
00115     new_size = SQLITE_MALLOC_SOFT_LIMIT/sizeof(struct _ht);
00116   }
00117   if( new_size==pH->htsize ) return;
00118 #endif
00119 
00120   /* There is a call to sqlite3_malloc() inside rehash(). If there is
00121   ** already an allocation at pH->ht, then if this malloc() fails it
00122   ** is benign (since failing to resize a hash table is a performance
00123   ** hit only, not a fatal error).
00124   */
00125   if( pH->htsize>0 ) sqlite3BeginBenignMalloc();
00126   new_ht = (struct _ht *)sqlite3MallocZero( new_size*sizeof(struct _ht) );
00127   if( pH->htsize>0 ) sqlite3EndBenignMalloc();
00128 
00129   if( new_ht==0 ) return;
00130   sqlite3_free(pH->ht);
00131   pH->ht = new_ht;
00132   pH->htsize = new_size;
00133   for(elem=pH->first, pH->first=0; elem; elem = next_elem){
00134     int h = strHash(elem->pKey, elem->nKey) & (new_size-1);
00135     next_elem = elem->next;
00136     insertElement(pH, &new_ht[h], elem);
00137   }
00138 }
00139 
00140 /* This function (for internal use only) locates an element in an
00141 ** hash table that matches the given key.  The hash for this key has
00142 ** already been computed and is passed as the 4th parameter.
00143 */
00144 static HashElem *findElementGivenHash(
00145   const Hash *pH,     /* The pH to be searched */
00146   const void *pKey,   /* The key we are searching for */
00147   int nKey,
00148   int h               /* The hash for this key. */
00149 ){
00150   HashElem *elem;                /* Used to loop thru the element list */
00151   int count;                     /* Number of elements left to test */
00152 
00153   if( pH->ht ){
00154     struct _ht *pEntry = &pH->ht[h];
00155     elem = pEntry->chain;
00156     count = pEntry->count;
00157     while( count-- && elem ){
00158       if( strCompare(elem->pKey,elem->nKey,pKey,nKey)==0 ){ 
00159         return elem;
00160       }
00161       elem = elem->next;
00162     }
00163   }
00164   return 0;
00165 }
00166 
00167 /* Remove a single entry from the hash table given a pointer to that
00168 ** element and a hash on the element's key.
00169 */
00170 static void removeElementGivenHash(
00171   Hash *pH,         /* The pH containing "elem" */
00172   HashElem* elem,   /* The element to be removed from the pH */
00173   int h             /* Hash value for the element */
00174 ){
00175   struct _ht *pEntry;
00176   if( elem->prev ){
00177     elem->prev->next = elem->next; 
00178   }else{
00179     pH->first = elem->next;
00180   }
00181   if( elem->next ){
00182     elem->next->prev = elem->prev;
00183   }
00184   pEntry = &pH->ht[h];
00185   if( pEntry->chain==elem ){
00186     pEntry->chain = elem->next;
00187   }
00188   pEntry->count--;
00189   if( pEntry->count<=0 ){
00190     pEntry->chain = 0;
00191   }
00192   if( pH->copyKey ){
00193     sqlite3_free(elem->pKey);
00194   }
00195   sqlite3_free( elem );
00196   pH->count--;
00197   if( pH->count<=0 ){
00198     assert( pH->first==0 );
00199     assert( pH->count==0 );
00200     sqlite3HashClear(pH);
00201   }
00202 }
00203 
00204 /* Attempt to locate an element of the hash table pH with a key
00205 ** that matches pKey,nKey.  Return a pointer to the corresponding 
00206 ** HashElem structure for this element if it is found, or NULL
00207 ** otherwise.
00208 */
00209 HashElem *sqlite3HashFindElem(const Hash *pH, const void *pKey, int nKey){
00210   int h;             /* A hash on key */
00211   HashElem *elem;    /* The element that matches key */
00212 
00213   if( pH==0 || pH->ht==0 ) return 0;
00214   h = strHash(pKey,nKey);
00215   elem = findElementGivenHash(pH,pKey,nKey, h % pH->htsize);
00216   return elem;
00217 }
00218 
00219 /* Attempt to locate an element of the hash table pH with a key
00220 ** that matches pKey,nKey.  Return the data for this element if it is
00221 ** found, or NULL if there is no match.
00222 */
00223 void *sqlite3HashFind(const Hash *pH, const void *pKey, int nKey){
00224   HashElem *elem;    /* The element that matches key */
00225   elem = sqlite3HashFindElem(pH, pKey, nKey);
00226   return elem ? elem->data : 0;
00227 }
00228 
00229 /* Insert an element into the hash table pH.  The key is pKey,nKey
00230 ** and the data is "data".
00231 **
00232 ** If no element exists with a matching key, then a new
00233 ** element is created.  A copy of the key is made if the copyKey
00234 ** flag is set.  NULL is returned.
00235 **
00236 ** If another element already exists with the same key, then the
00237 ** new data replaces the old data and the old data is returned.
00238 ** The key is not copied in this instance.  If a malloc fails, then
00239 ** the new data is returned and the hash table is unchanged.
00240 **
00241 ** If the "data" parameter to this function is NULL, then the
00242 ** element corresponding to "key" is removed from the hash table.
00243 */
00244 void *sqlite3HashInsert(Hash *pH, const void *pKey, int nKey, void *data){
00245   int hraw;             /* Raw hash value of the key */
00246   int h;                /* the hash of the key modulo hash table size */
00247   HashElem *elem;       /* Used to loop thru the element list */
00248   HashElem *new_elem;   /* New element added to the pH */
00249 
00250   assert( pH!=0 );
00251   hraw = strHash(pKey, nKey);
00252   if( pH->htsize ){
00253     h = hraw % pH->htsize;
00254     elem = findElementGivenHash(pH,pKey,nKey,h);
00255     if( elem ){
00256       void *old_data = elem->data;
00257       if( data==0 ){
00258         removeElementGivenHash(pH,elem,h);
00259       }else{
00260         elem->data = data;
00261         if( !pH->copyKey ){
00262           elem->pKey = (void *)pKey;
00263         }
00264         assert(nKey==elem->nKey);
00265       }
00266       return old_data;
00267     }
00268   }
00269   if( data==0 ) return 0;
00270   new_elem = (HashElem*)sqlite3Malloc( sizeof(HashElem) );
00271   if( new_elem==0 ) return data;
00272   if( pH->copyKey && pKey!=0 ){
00273     new_elem->pKey = sqlite3Malloc( nKey );
00274     if( new_elem->pKey==0 ){
00275       sqlite3_free(new_elem);
00276       return data;
00277     }
00278     memcpy((void*)new_elem->pKey, pKey, nKey);
00279   }else{
00280     new_elem->pKey = (void*)pKey;
00281   }
00282   new_elem->nKey = nKey;
00283   pH->count++;
00284   if( pH->htsize==0 ){
00285     rehash(pH, 128/sizeof(pH->ht[0]));
00286     if( pH->htsize==0 ){
00287       pH->count = 0;
00288       if( pH->copyKey ){
00289         sqlite3_free(new_elem->pKey);
00290       }
00291       sqlite3_free(new_elem);
00292       return data;
00293     }
00294   }
00295   if( pH->count > pH->htsize ){
00296     rehash(pH,pH->htsize*2);
00297   }
00298   assert( pH->htsize>0 );
00299   h = hraw % pH->htsize;
00300   insertElement(pH, &pH->ht[h], new_elem);
00301   new_elem->data = data;
00302   return 0;
00303 }

ContextLogger2—ContextLogger2 Logger Daemon Internals—Generated on Mon May 2 13:49:54 2011 by Doxygen 1.6.1