1 /* 2 ** 2001 September 22 3 ** 4 ** The author disclaims copyright to this source code. In place of 5 ** 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-tables 13 ** used in SQLite. 14 ** 15 ** $Id: hash.c,v 1.33 2009/01/09 01:12:28 drh Exp $ 16 */ 17 #include "sqliteInt.h" 18 #include <assert.h> 19 20 /* Turn bulk memory into a hash table object by initializing the 21 ** fields of the Hash structure. 22 ** 23 ** "pNew" is a pointer to the hash table that is to be initialized. 24 ** "copyKey" is true if the hash table should make its own private 25 ** copy of keys and false if it should just use the supplied pointer. 26 */ 27 void sqlite3HashInit(Hash *pNew, int copyKey){ 28 assert( pNew!=0 ); 29 pNew->copyKey = copyKey!=0; 30 pNew->first = 0; 31 pNew->count = 0; 32 pNew->htsize = 0; 33 pNew->ht = 0; 34 } 35 36 /* Remove all entries from a hash table. Reclaim all memory. 37 ** Call this routine to delete a hash table or to reset a hash table 38 ** to the empty state. 39 */ 40 void sqlite3HashClear(Hash *pH){ 41 HashElem *elem; /* For looping over all elements of the table */ 42 43 assert( pH!=0 ); 44 elem = pH->first; 45 pH->first = 0; 46 sqlite3_free(pH->ht); 47 pH->ht = 0; 48 pH->htsize = 0; 49 while( elem ){ 50 HashElem *next_elem = elem->next; 51 if( pH->copyKey ){ 52 sqlite3_free(elem->pKey); 53 } 54 sqlite3_free(elem); 55 elem = next_elem; 56 } 57 pH->count = 0; 58 } 59 60 /* 61 ** Hash and comparison functions when the mode is SQLITE_HASH_STRING 62 */ 63 static int strHash(const void *pKey, int nKey){ 64 const char *z = (const char *)pKey; 65 int h = 0; 66 if( nKey<=0 ) nKey = sqlite3Strlen30(z); 67 while( nKey > 0 ){ 68 h = (h<<3) ^ h ^ sqlite3UpperToLower[(unsigned char)*z++]; 69 nKey--; 70 } 71 return h & 0x7fffffff; 72 } 73 static int strCompare(const void *pKey1, int n1, const void *pKey2, int n2){ 74 if( n1!=n2 ) return 1; 75 return sqlite3StrNICmp((const char*)pKey1,(const char*)pKey2,n1); 76 } 77 78 79 /* Link an element into the hash table 80 */ 81 static void insertElement( 82 Hash *pH, /* The complete hash table */ 83 struct _ht *pEntry, /* The entry into which pNew is inserted */ 84 HashElem *pNew /* The element to be inserted */ 85 ){ 86 HashElem *pHead; /* First element already in pEntry */ 87 pHead = pEntry->chain; 88 if( pHead ){ 89 pNew->next = pHead; 90 pNew->prev = pHead->prev; 91 if( pHead->prev ){ pHead->prev->next = pNew; } 92 else { pH->first = pNew; } 93 pHead->prev = pNew; 94 }else{ 95 pNew->next = pH->first; 96 if( pH->first ){ pH->first->prev = pNew; } 97 pNew->prev = 0; 98 pH->first = pNew; 99 } 100 pEntry->count++; 101 pEntry->chain = pNew; 102 } 103 104 105 /* Resize the hash table so that it cantains "new_size" buckets. 106 ** "new_size" must be a power of 2. The hash table might fail 107 ** to resize if sqlite3_malloc() fails. 108 */ 109 static void rehash(Hash *pH, int new_size){ 110 struct _ht *new_ht; /* The new hash table */ 111 HashElem *elem, *next_elem; /* For looping over existing elements */ 112 113 #ifdef SQLITE_MALLOC_SOFT_LIMIT 114 if( new_size*sizeof(struct _ht)>SQLITE_MALLOC_SOFT_LIMIT ){ 115 new_size = SQLITE_MALLOC_SOFT_LIMIT/sizeof(struct _ht); 116 } 117 if( new_size==pH->htsize ) return; 118 #endif 119 120 /* There is a call to sqlite3_malloc() inside rehash(). If there is 121 ** already an allocation at pH->ht, then if this malloc() fails it 122 ** is benign (since failing to resize a hash table is a performance 123 ** hit only, not a fatal error). 124 */ 125 if( pH->htsize>0 ) sqlite3BeginBenignMalloc(); 126 new_ht = (struct _ht *)sqlite3MallocZero( new_size*sizeof(struct _ht) ); 127 if( pH->htsize>0 ) sqlite3EndBenignMalloc(); 128 129 if( new_ht==0 ) return; 130 sqlite3_free(pH->ht); 131 pH->ht = new_ht; 132 pH->htsize = new_size; 133 for(elem=pH->first, pH->first=0; elem; elem = next_elem){ 134 int h = strHash(elem->pKey, elem->nKey) & (new_size-1); 135 next_elem = elem->next; 136 insertElement(pH, &new_ht[h], elem); 137 } 138 } 139 140 /* This function (for internal use only) locates an element in an 141 ** hash table that matches the given key. The hash for this key has 142 ** already been computed and is passed as the 4th parameter. 143 */ 144 static HashElem *findElementGivenHash( 145 const Hash *pH, /* The pH to be searched */ 146 const void *pKey, /* The key we are searching for */ 147 int nKey, 148 int h /* The hash for this key. */ 149 ){ 150 HashElem *elem; /* Used to loop thru the element list */ 151 int count; /* Number of elements left to test */ 152 153 if( pH->ht ){ 154 struct _ht *pEntry = &pH->ht[h]; 155 elem = pEntry->chain; 156 count = pEntry->count; 157 while( count-- && elem ){ 158 if( strCompare(elem->pKey,elem->nKey,pKey,nKey)==0 ){ 159 return elem; 160 } 161 elem = elem->next; 162 } 163 } 164 return 0; 165 } 166 167 /* Remove a single entry from the hash table given a pointer to that 168 ** element and a hash on the element's key. 169 */ 170 static void removeElementGivenHash( 171 Hash *pH, /* The pH containing "elem" */ 172 HashElem* elem, /* The element to be removed from the pH */ 173 int h /* Hash value for the element */ 174 ){ 175 struct _ht *pEntry; 176 if( elem->prev ){ 177 elem->prev->next = elem->next; 178 }else{ 179 pH->first = elem->next; 180 } 181 if( elem->next ){ 182 elem->next->prev = elem->prev; 183 } 184 pEntry = &pH->ht[h]; 185 if( pEntry->chain==elem ){ 186 pEntry->chain = elem->next; 187 } 188 pEntry->count--; 189 if( pEntry->count<=0 ){ 190 pEntry->chain = 0; 191 } 192 if( pH->copyKey ){ 193 sqlite3_free(elem->pKey); 194 } 195 sqlite3_free( elem ); 196 pH->count--; 197 if( pH->count<=0 ){ 198 assert( pH->first==0 ); 199 assert( pH->count==0 ); 200 sqlite3HashClear(pH); 201 } 202 } 203 204 /* Attempt to locate an element of the hash table pH with a key 205 ** that matches pKey,nKey. Return a pointer to the corresponding 206 ** HashElem structure for this element if it is found, or NULL 207 ** otherwise. 208 */ 209 HashElem *sqlite3HashFindElem(const Hash *pH, const void *pKey, int nKey){ 210 int h; /* A hash on key */ 211 HashElem *elem; /* The element that matches key */ 212 213 if( pH==0 || pH->ht==0 ) return 0; 214 h = strHash(pKey,nKey); 215 elem = findElementGivenHash(pH,pKey,nKey, h % pH->htsize); 216 return elem; 217 } 218 219 /* Attempt to locate an element of the hash table pH with a key 220 ** that matches pKey,nKey. Return the data for this element if it is 221 ** found, or NULL if there is no match. 222 */ 223 void *sqlite3HashFind(const Hash *pH, const void *pKey, int nKey){ 224 HashElem *elem; /* The element that matches key */ 225 elem = sqlite3HashFindElem(pH, pKey, nKey); 226 return elem ? elem->data : 0; 227 } 228 229 /* Insert an element into the hash table pH. The key is pKey,nKey 230 ** and the data is "data". 231 ** 232 ** If no element exists with a matching key, then a new 233 ** element is created. A copy of the key is made if the copyKey 234 ** flag is set. NULL is returned. 235 ** 236 ** If another element already exists with the same key, then the 237 ** new data replaces the old data and the old data is returned. 238 ** The key is not copied in this instance. If a malloc fails, then 239 ** the new data is returned and the hash table is unchanged. 240 ** 241 ** If the "data" parameter to this function is NULL, then the 242 ** element corresponding to "key" is removed from the hash table. 243 */ 244 void *sqlite3HashInsert(Hash *pH, const void *pKey, int nKey, void *data){ 245 int hraw; /* Raw hash value of the key */ 246 int h; /* the hash of the key modulo hash table size */ 247 HashElem *elem; /* Used to loop thru the element list */ 248 HashElem *new_elem; /* New element added to the pH */ 249 250 assert( pH!=0 ); 251 hraw = strHash(pKey, nKey); 252 if( pH->htsize ){ 253 h = hraw % pH->htsize; 254 elem = findElementGivenHash(pH,pKey,nKey,h); 255 if( elem ){ 256 void *old_data = elem->data; 257 if( data==0 ){ 258 removeElementGivenHash(pH,elem,h); 259 }else{ 260 elem->data = data; 261 if( !pH->copyKey ){ 262 elem->pKey = (void *)pKey; 263 } 264 assert(nKey==elem->nKey); 265 } 266 return old_data; 267 } 268 } 269 if( data==0 ) return 0; 270 new_elem = (HashElem*)sqlite3Malloc( sizeof(HashElem) ); 271 if( new_elem==0 ) return data; 272 if( pH->copyKey && pKey!=0 ){ 273 new_elem->pKey = sqlite3Malloc( nKey ); 274 if( new_elem->pKey==0 ){ 275 sqlite3_free(new_elem); 276 return data; 277 } 278 memcpy((void*)new_elem->pKey, pKey, nKey); 279 }else{ 280 new_elem->pKey = (void*)pKey; 281 } 282 new_elem->nKey = nKey; 283 pH->count++; 284 if( pH->htsize==0 ){ 285 rehash(pH, 128/sizeof(pH->ht[0])); 286 if( pH->htsize==0 ){ 287 pH->count = 0; 288 if( pH->copyKey ){ 289 sqlite3_free(new_elem->pKey); 290 } 291 sqlite3_free(new_elem); 292 return data; 293 } 294 } 295 if( pH->count > pH->htsize ){ 296 rehash(pH,pH->htsize*2); 297 } 298 assert( pH->htsize>0 ); 299 h = hraw % pH->htsize; 300 insertElement(pH, &pH->ht[h], new_elem); 301 new_elem->data = data; 302 return 0; 303 } 304