blob: 59dbf11d60d98f8fd4593ce38f45e9bac900b345 [file] [log] [blame]
drhbeae3192001-09-22 18:12:08 +00001/*
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**
drh5a2c2c22001-11-21 02:21:11 +000015** $Id: hash.c,v 1.4 2001/11/21 02:21:12 drh Exp $
drhbeae3192001-09-22 18:12:08 +000016*/
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*/
23void sqliteHashInit(Hash *new, int keyClass, int copyKey){
24 assert( new!=0 );
25 assert( keyClass>=SQLITE_HASH_INT && keyClass<=SQLITE_HASH_BINARY );
26 new->keyClass = keyClass;
27 new->copyKey = copyKey &&
28 (keyClass==SQLITE_HASH_STRING || keyClass==SQLITE_HASH_BINARY);
29 new->first = 0;
30 new->count = 0;
31 new->htsize = 0;
32 new->ht = 0;
33}
34
35/* Remove all entries from a hash table. Reclaim all memory.
36*/
37void sqliteHashClear(Hash *pH){
38 HashElem *elem; /* For looping over all elements of the table */
39
40 assert( pH!=0 );
41 elem = pH->first;
42 pH->first = 0;
43 if( pH->ht ) sqliteFree(pH->ht);
44 pH->ht = 0;
45 pH->htsize = 0;
46 while( elem ){
47 HashElem *next_elem = elem->next;
48 if( pH->copyKey && elem->pKey ){
49 sqliteFree(elem->pKey);
50 }
51 sqliteFree(elem);
52 elem = next_elem;
53 }
54 pH->count = 0;
55}
56
57/*
58** Hash and comparison functions when the mode is SQLITE_HASH_INT
59*/
60static int intHash(const void *pKey, int nKey){
61 return nKey ^ (nKey<<8) ^ (nKey>>8);
62}
63static int intCompare(const void *pKey1, int n1, const void *pKey2, int n2){
64 return n2 - n1;
65}
66
67/*
68** Hash and comparison functions when the mode is SQLITE_HASH_POINTER
69*/
70static int ptrHash(const void *pKey, int nKey){
drh5a2c2c22001-11-21 02:21:11 +000071 uptr x = Addr(pKey);
72 return x ^ (x<<8) ^ (x>>8);
drhbeae3192001-09-22 18:12:08 +000073}
74static int ptrCompare(const void *pKey1, int n1, const void *pKey2, int n2){
drh5a2c2c22001-11-21 02:21:11 +000075 if( pKey1==pKey2 ) return 0;
76 if( pKey1<pKey2 ) return -1;
77 return 1;
drhbeae3192001-09-22 18:12:08 +000078}
79
80/*
81** Hash and comparison functions when the mode is SQLITE_HASH_STRING
82*/
83static int strHash(const void *pKey, int nKey){
84 return sqliteHashNoCase((const char*)pKey, nKey);
85}
86static int strCompare(const void *pKey1, int n1, const void *pKey2, int n2){
87 if( n1!=n2 ) return n2-n1;
88 return sqliteStrNICmp((const char*)pKey1,(const char*)pKey2,n1);
89}
90
91/*
92** Hash and comparison functions when the mode is SQLITE_HASH_BINARY
93*/
94static int binHash(const void *pKey, int nKey){
95 int h = 0;
96 const char *z = (const char *)pKey;
97 while( nKey-- > 0 ){
98 h = (h<<3) ^ h ^ *(z++);
99 }
100 if( h<0 ) h = -h;
101 return h;
102}
103static int binCompare(const void *pKey1, int n1, const void *pKey2, int n2){
104 if( n1!=n2 ) return n2-n1;
105 return memcmp(pKey1,pKey2,n1);
106}
107
108/*
109** Return a pointer to the appropriate hash function given the key class.
110*/
111static int (*hashFunction(int keyClass))(const void*,int){
112 switch( keyClass ){
113 case SQLITE_HASH_INT: return intHash;
114 case SQLITE_HASH_POINTER: return ptrHash;
115 case SQLITE_HASH_STRING: return strHash;
116 case SQLITE_HASH_BINARY: return binHash;;
117 default: break;
118 }
119 return 0;
120}
121
122/*
123** Return a pointer to the appropriate hash function given the key class.
124*/
125static int (*compareFunction(int keyClass))(const void*,int,const void*,int){
126 switch( keyClass ){
127 case SQLITE_HASH_INT: return intCompare;
128 case SQLITE_HASH_POINTER: return ptrCompare;
129 case SQLITE_HASH_STRING: return strCompare;
130 case SQLITE_HASH_BINARY: return binCompare;
131 default: break;
132 }
133 return 0;
134}
135
136
137/* Resize the hash table. new_size must be a power of 2.
138** The hash table might fail to resize if sqliteMalloc() fails.
139*/
140static void rehash(Hash *pH, int new_size){
141 struct _ht *new_ht; /* The new hash table */
142 HashElem *elem, *next_elem; /* For looping over existing elements */
143 HashElem *x; /* Element being copied to new hash table */
144 int (*xHash)(const void*,int); /* The hash function */
145
146 assert( (new_size & (new_size-1))==0 );
147 new_ht = (struct _ht *)sqliteMalloc( new_size*sizeof(struct _ht) );
148 if( new_ht==0 ) return;
149 if( pH->ht ) sqliteFree(pH->ht);
150 pH->ht = new_ht;
151 pH->htsize = new_size;
152 xHash = hashFunction(pH->keyClass);
153 for(elem=pH->first, pH->first=0; elem; elem = next_elem){
154 int h = (*xHash)(elem->pKey, elem->nKey) & (new_size-1);
155 next_elem = elem->next;
156 x = new_ht[h].chain;
157 if( x ){
158 elem->next = x;
159 elem->prev = x->prev;
160 if( x->prev ) x->prev->next = elem;
161 else pH->first = elem;
162 x->prev = elem;
163 }else{
164 elem->next = pH->first;
165 if( pH->first ) pH->first->prev = elem;
166 elem->prev = 0;
167 pH->first = elem;
168 }
169 new_ht[h].chain = elem;
170 new_ht[h].count++;
171 }
172}
173
174/* This function (for internal use only) locates an element in an
175** pH that matches the given key. The hash for this key has
176** already been computed and is passed as the 3rd parameter.
177*/
178static HashElem *findElementGivenHash(
179 const Hash *pH, /* The pH to be searched */
180 const void *pKey, /* The key we are searching for */
181 int nKey,
182 int h /* The hash for this key. */
183){
184 HashElem *elem; /* Used to loop thru the element list */
185 int count; /* Number of elements left to test */
186 int (*xCompare)(const void*,int,const void*,int); /* comparison function */
187
188 if( pH->ht ){
189 elem = pH->ht[h].chain;
190 count = pH->ht[h].count;
191 xCompare = compareFunction(pH->keyClass);
192 while( count-- && elem ){
193 if( (*xCompare)(elem->pKey,elem->nKey,pKey,nKey)==0 ){
194 return elem;
195 }
196 elem = elem->next;
197 }
198 }
199 return 0;
200}
201
drh81a20f22001-10-12 17:30:04 +0000202/* Remove a single entry from the hash table given a pointer to that
drhbeae3192001-09-22 18:12:08 +0000203** element and a hash on the element's key.
204*/
205static void removeElementGivenHash(
206 Hash *pH, /* The pH containing "elem" */
207 HashElem* elem, /* The element to be removed from the pH */
208 int h /* Hash value for the element */
209){
210 if( elem->prev ){
211 elem->prev->next = elem->next;
212 }else{
213 pH->first = elem->next;
214 }
215 if( elem->next ){
216 elem->next->prev = elem->prev;
217 }
218 if( pH->ht[h].chain==elem ){
219 pH->ht[h].chain = elem->next;
220 }
221 pH->ht[h].count--;
222 if( pH->ht[h].count<=0 ){
223 pH->ht[h].chain = 0;
224 }
225 if( pH->copyKey && elem->pKey ){
226 sqliteFree(elem->pKey);
227 }
228 sqliteFree( elem );
229 pH->count--;
230}
231
232/* Attempt to locate an element of the associative pH with a key
drh81a20f22001-10-12 17:30:04 +0000233** that matches pKey,nKey. Return the data for this element if it is
drhbeae3192001-09-22 18:12:08 +0000234** found, or NULL if no match is found.
235*/
236void *sqliteHashFind(const Hash *pH, const void *pKey, int nKey){
237 int h; /* A hash on key */
238 HashElem *elem; /* The element that matches key */
239 int (*xHash)(const void*,int); /* The hash function */
240
241 if( pH==0 || pH->ht==0 ) return 0;
242 xHash = hashFunction(pH->keyClass);
243 assert( xHash!=0 );
244 h = (*xHash)(pKey,nKey);
245 assert( (pH->htsize & (pH->htsize-1))==0 );
246 elem = findElementGivenHash(pH,pKey,nKey, h & (pH->htsize-1));
247 return elem ? elem->data : 0;
248}
249
drh81a20f22001-10-12 17:30:04 +0000250/* Insert an element into the hash table pH. The key is pKey,nKey
251** and the data is "data".
drhbeae3192001-09-22 18:12:08 +0000252**
drh81a20f22001-10-12 17:30:04 +0000253** If no element exists with a matching key, then a new
254** element is created. A copy of the key is made if the copyKey
255** flag is set. NULL is returned.
drhbeae3192001-09-22 18:12:08 +0000256**
257** If another element already exists with the same key, then the
258** new data replaces the old data and the old data is returned.
drh6d4abfb2001-10-22 02:58:08 +0000259** The key is not copied in this instance. If a malloc fails, then
260** new data is returned.
drhbeae3192001-09-22 18:12:08 +0000261**
262** If the "data" parameter to this function is NULL, then the
drh81a20f22001-10-12 17:30:04 +0000263** element corresponding to "key" is removed from the hash table.
drhbeae3192001-09-22 18:12:08 +0000264*/
265void *sqliteHashInsert(Hash *pH, void *pKey, int nKey, void *data){
266 int hraw; /* Raw hash value of the key */
267 int h; /* the hash of the key modulo hash table size */
268 HashElem *elem; /* Used to loop thru the element list */
269 HashElem *new_elem; /* New element added to the pH */
270 int (*xHash)(const void*,int); /* The hash function */
271
272 assert( pH!=0 );
273 xHash = hashFunction(pH->keyClass);
274 assert( xHash!=0 );
275 hraw = (*xHash)(pKey, nKey);
276 assert( (pH->htsize & (pH->htsize-1))==0 );
277 h = hraw & (pH->htsize-1);
278 elem = findElementGivenHash(pH,pKey,nKey,h);
279 if( elem ){
280 void *old_data = elem->data;
281 if( data==0 ){
282 removeElementGivenHash(pH,elem,h);
283 }else{
284 elem->data = data;
285 }
286 return old_data;
287 }
288 if( data==0 ) return 0;
289 new_elem = (HashElem*)sqliteMalloc( sizeof(HashElem) );
drh6d4abfb2001-10-22 02:58:08 +0000290 if( new_elem==0 ) return data;
drhbeae3192001-09-22 18:12:08 +0000291 if( pH->copyKey && pKey!=0 ){
292 new_elem->pKey = sqliteMalloc( nKey );
293 if( new_elem->pKey==0 ){
294 sqliteFree(new_elem);
drh6d4abfb2001-10-22 02:58:08 +0000295 return data;
drhbeae3192001-09-22 18:12:08 +0000296 }
297 memcpy((void*)new_elem->pKey, pKey, nKey);
298 }else{
299 new_elem->pKey = pKey;
300 }
301 new_elem->nKey = nKey;
302 pH->count++;
303 if( pH->htsize==0 ) rehash(pH,8);
304 if( pH->htsize==0 ){
305 pH->count = 0;
306 sqliteFree(new_elem);
drh6d4abfb2001-10-22 02:58:08 +0000307 return data;
drhbeae3192001-09-22 18:12:08 +0000308 }
309 if( pH->count > pH->htsize ){
310 rehash(pH,pH->htsize*2);
311 }
312 assert( (pH->htsize & (pH->htsize-1))==0 );
313 h = hraw & (pH->htsize-1);
314 elem = pH->ht[h].chain;
315 if( elem ){
316 new_elem->next = elem;
317 new_elem->prev = elem->prev;
318 if( elem->prev ){ elem->prev->next = new_elem; }
319 else { pH->first = new_elem; }
320 elem->prev = new_elem;
321 }else{
322 new_elem->next = pH->first;
323 new_elem->prev = 0;
324 if( pH->first ){ pH->first->prev = new_elem; }
325 pH->first = new_elem;
326 }
327 pH->ht[h].count++;
328 pH->ht[h].chain = new_elem;
329 new_elem->data = data;
330 return 0;
331}