diff options
Diffstat (limited to '')
-rwxr-xr-x | libraries/sqlite/win32/hash.c | 418 |
1 files changed, 418 insertions, 0 deletions
diff --git a/libraries/sqlite/win32/hash.c b/libraries/sqlite/win32/hash.c new file mode 100755 index 0000000..a88d16b --- /dev/null +++ b/libraries/sqlite/win32/hash.c | |||
@@ -0,0 +1,418 @@ | |||
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.24 2007/09/04 14:31:47 danielk1977 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 | ** keyClass is one of the constants SQLITE_HASH_INT, SQLITE_HASH_POINTER, | ||
25 | ** SQLITE_HASH_BINARY, or SQLITE_HASH_STRING. The value of keyClass | ||
26 | ** determines what kind of key the hash table will use. "copyKey" is | ||
27 | ** true if the hash table should make its own private copy of keys and | ||
28 | ** false if it should just use the supplied pointer. CopyKey only makes | ||
29 | ** sense for SQLITE_HASH_STRING and SQLITE_HASH_BINARY and is ignored | ||
30 | ** for other key classes. | ||
31 | */ | ||
32 | void sqlite3HashInit(Hash *pNew, int keyClass, int copyKey){ | ||
33 | assert( pNew!=0 ); | ||
34 | assert( keyClass>=SQLITE_HASH_STRING && keyClass<=SQLITE_HASH_BINARY ); | ||
35 | pNew->keyClass = keyClass; | ||
36 | #if 0 | ||
37 | if( keyClass==SQLITE_HASH_POINTER || keyClass==SQLITE_HASH_INT ) copyKey = 0; | ||
38 | #endif | ||
39 | pNew->copyKey = copyKey; | ||
40 | pNew->first = 0; | ||
41 | pNew->count = 0; | ||
42 | pNew->htsize = 0; | ||
43 | pNew->ht = 0; | ||
44 | } | ||
45 | |||
46 | /* Remove all entries from a hash table. Reclaim all memory. | ||
47 | ** Call this routine to delete a hash table or to reset a hash table | ||
48 | ** to the empty state. | ||
49 | */ | ||
50 | void sqlite3HashClear(Hash *pH){ | ||
51 | HashElem *elem; /* For looping over all elements of the table */ | ||
52 | |||
53 | assert( pH!=0 ); | ||
54 | elem = pH->first; | ||
55 | pH->first = 0; | ||
56 | if( pH->ht ) sqlite3_free(pH->ht); | ||
57 | pH->ht = 0; | ||
58 | pH->htsize = 0; | ||
59 | while( elem ){ | ||
60 | HashElem *next_elem = elem->next; | ||
61 | if( pH->copyKey && elem->pKey ){ | ||
62 | sqlite3_free(elem->pKey); | ||
63 | } | ||
64 | sqlite3_free(elem); | ||
65 | elem = next_elem; | ||
66 | } | ||
67 | pH->count = 0; | ||
68 | } | ||
69 | |||
70 | #if 0 /* NOT USED */ | ||
71 | /* | ||
72 | ** Hash and comparison functions when the mode is SQLITE_HASH_INT | ||
73 | */ | ||
74 | static int intHash(const void *pKey, int nKey){ | ||
75 | return nKey ^ (nKey<<8) ^ (nKey>>8); | ||
76 | } | ||
77 | static int intCompare(const void *pKey1, int n1, const void *pKey2, int n2){ | ||
78 | return n2 - n1; | ||
79 | } | ||
80 | #endif | ||
81 | |||
82 | #if 0 /* NOT USED */ | ||
83 | /* | ||
84 | ** Hash and comparison functions when the mode is SQLITE_HASH_POINTER | ||
85 | */ | ||
86 | static int ptrHash(const void *pKey, int nKey){ | ||
87 | uptr x = Addr(pKey); | ||
88 | return x ^ (x<<8) ^ (x>>8); | ||
89 | } | ||
90 | static int ptrCompare(const void *pKey1, int n1, const void *pKey2, int n2){ | ||
91 | if( pKey1==pKey2 ) return 0; | ||
92 | if( pKey1<pKey2 ) return -1; | ||
93 | return 1; | ||
94 | } | ||
95 | #endif | ||
96 | |||
97 | /* | ||
98 | ** Hash and comparison functions when the mode is SQLITE_HASH_STRING | ||
99 | */ | ||
100 | static int strHash(const void *pKey, int nKey){ | ||
101 | const char *z = (const char *)pKey; | ||
102 | int h = 0; | ||
103 | if( nKey<=0 ) nKey = strlen(z); | ||
104 | while( nKey > 0 ){ | ||
105 | h = (h<<3) ^ h ^ sqlite3UpperToLower[(unsigned char)*z++]; | ||
106 | nKey--; | ||
107 | } | ||
108 | return h & 0x7fffffff; | ||
109 | } | ||
110 | static int strCompare(const void *pKey1, int n1, const void *pKey2, int n2){ | ||
111 | if( n1!=n2 ) return 1; | ||
112 | return sqlite3StrNICmp((const char*)pKey1,(const char*)pKey2,n1); | ||
113 | } | ||
114 | |||
115 | /* | ||
116 | ** Hash and comparison functions when the mode is SQLITE_HASH_BINARY | ||
117 | */ | ||
118 | static int binHash(const void *pKey, int nKey){ | ||
119 | int h = 0; | ||
120 | const char *z = (const char *)pKey; | ||
121 | while( nKey-- > 0 ){ | ||
122 | h = (h<<3) ^ h ^ *(z++); | ||
123 | } | ||
124 | return h & 0x7fffffff; | ||
125 | } | ||
126 | static int binCompare(const void *pKey1, int n1, const void *pKey2, int n2){ | ||
127 | if( n1!=n2 ) return 1; | ||
128 | return memcmp(pKey1,pKey2,n1); | ||
129 | } | ||
130 | |||
131 | /* | ||
132 | ** Return a pointer to the appropriate hash function given the key class. | ||
133 | ** | ||
134 | ** The C syntax in this function definition may be unfamilar to some | ||
135 | ** programmers, so we provide the following additional explanation: | ||
136 | ** | ||
137 | ** The name of the function is "hashFunction". The function takes a | ||
138 | ** single parameter "keyClass". The return value of hashFunction() | ||
139 | ** is a pointer to another function. Specifically, the return value | ||
140 | ** of hashFunction() is a pointer to a function that takes two parameters | ||
141 | ** with types "const void*" and "int" and returns an "int". | ||
142 | */ | ||
143 | static int (*hashFunction(int keyClass))(const void*,int){ | ||
144 | #if 0 /* HASH_INT and HASH_POINTER are never used */ | ||
145 | switch( keyClass ){ | ||
146 | case SQLITE_HASH_INT: return &intHash; | ||
147 | case SQLITE_HASH_POINTER: return &ptrHash; | ||
148 | case SQLITE_HASH_STRING: return &strHash; | ||
149 | case SQLITE_HASH_BINARY: return &binHash;; | ||
150 | default: break; | ||
151 | } | ||
152 | return 0; | ||
153 | #else | ||
154 | if( keyClass==SQLITE_HASH_STRING ){ | ||
155 | return &strHash; | ||
156 | }else{ | ||
157 | assert( keyClass==SQLITE_HASH_BINARY ); | ||
158 | return &binHash; | ||
159 | } | ||
160 | #endif | ||
161 | } | ||
162 | |||
163 | /* | ||
164 | ** Return a pointer to the appropriate hash function given the key class. | ||
165 | ** | ||
166 | ** For help in interpreted the obscure C code in the function definition, | ||
167 | ** see the header comment on the previous function. | ||
168 | */ | ||
169 | static int (*compareFunction(int keyClass))(const void*,int,const void*,int){ | ||
170 | #if 0 /* HASH_INT and HASH_POINTER are never used */ | ||
171 | switch( keyClass ){ | ||
172 | case SQLITE_HASH_INT: return &intCompare; | ||
173 | case SQLITE_HASH_POINTER: return &ptrCompare; | ||
174 | case SQLITE_HASH_STRING: return &strCompare; | ||
175 | case SQLITE_HASH_BINARY: return &binCompare; | ||
176 | default: break; | ||
177 | } | ||
178 | return 0; | ||
179 | #else | ||
180 | if( keyClass==SQLITE_HASH_STRING ){ | ||
181 | return &strCompare; | ||
182 | }else{ | ||
183 | assert( keyClass==SQLITE_HASH_BINARY ); | ||
184 | return &binCompare; | ||
185 | } | ||
186 | #endif | ||
187 | } | ||
188 | |||
189 | /* Link an element into the hash table | ||
190 | */ | ||
191 | static void insertElement( | ||
192 | Hash *pH, /* The complete hash table */ | ||
193 | struct _ht *pEntry, /* The entry into which pNew is inserted */ | ||
194 | HashElem *pNew /* The element to be inserted */ | ||
195 | ){ | ||
196 | HashElem *pHead; /* First element already in pEntry */ | ||
197 | pHead = pEntry->chain; | ||
198 | if( pHead ){ | ||
199 | pNew->next = pHead; | ||
200 | pNew->prev = pHead->prev; | ||
201 | if( pHead->prev ){ pHead->prev->next = pNew; } | ||
202 | else { pH->first = pNew; } | ||
203 | pHead->prev = pNew; | ||
204 | }else{ | ||
205 | pNew->next = pH->first; | ||
206 | if( pH->first ){ pH->first->prev = pNew; } | ||
207 | pNew->prev = 0; | ||
208 | pH->first = pNew; | ||
209 | } | ||
210 | pEntry->count++; | ||
211 | pEntry->chain = pNew; | ||
212 | } | ||
213 | |||
214 | |||
215 | /* Resize the hash table so that it cantains "new_size" buckets. | ||
216 | ** "new_size" must be a power of 2. The hash table might fail | ||
217 | ** to resize if sqlite3_malloc() fails. | ||
218 | */ | ||
219 | static void rehash(Hash *pH, int new_size){ | ||
220 | struct _ht *new_ht; /* The new hash table */ | ||
221 | HashElem *elem, *next_elem; /* For looping over existing elements */ | ||
222 | int (*xHash)(const void*,int); /* The hash function */ | ||
223 | |||
224 | assert( (new_size & (new_size-1))==0 ); | ||
225 | |||
226 | /* There is a call to sqlite3_malloc() inside rehash(). If there is | ||
227 | ** already an allocation at pH->ht, then if this malloc() fails it | ||
228 | ** is benign (since failing to resize a hash table is a performance | ||
229 | ** hit only, not a fatal error). | ||
230 | */ | ||
231 | sqlite3MallocBenignFailure(pH->htsize>0); | ||
232 | |||
233 | new_ht = (struct _ht *)sqlite3MallocZero( new_size*sizeof(struct _ht) ); | ||
234 | if( new_ht==0 ) return; | ||
235 | if( pH->ht ) sqlite3_free(pH->ht); | ||
236 | pH->ht = new_ht; | ||
237 | pH->htsize = new_size; | ||
238 | xHash = hashFunction(pH->keyClass); | ||
239 | for(elem=pH->first, pH->first=0; elem; elem = next_elem){ | ||
240 | int h = (*xHash)(elem->pKey, elem->nKey) & (new_size-1); | ||
241 | next_elem = elem->next; | ||
242 | insertElement(pH, &new_ht[h], elem); | ||
243 | } | ||
244 | } | ||
245 | |||
246 | /* This function (for internal use only) locates an element in an | ||
247 | ** hash table that matches the given key. The hash for this key has | ||
248 | ** already been computed and is passed as the 4th parameter. | ||
249 | */ | ||
250 | static HashElem *findElementGivenHash( | ||
251 | const Hash *pH, /* The pH to be searched */ | ||
252 | const void *pKey, /* The key we are searching for */ | ||
253 | int nKey, | ||
254 | int h /* The hash for this key. */ | ||
255 | ){ | ||
256 | HashElem *elem; /* Used to loop thru the element list */ | ||
257 | int count; /* Number of elements left to test */ | ||
258 | int (*xCompare)(const void*,int,const void*,int); /* comparison function */ | ||
259 | |||
260 | if( pH->ht ){ | ||
261 | struct _ht *pEntry = &pH->ht[h]; | ||
262 | elem = pEntry->chain; | ||
263 | count = pEntry->count; | ||
264 | xCompare = compareFunction(pH->keyClass); | ||
265 | while( count-- && elem ){ | ||
266 | if( (*xCompare)(elem->pKey,elem->nKey,pKey,nKey)==0 ){ | ||
267 | return elem; | ||
268 | } | ||
269 | elem = elem->next; | ||
270 | } | ||
271 | } | ||
272 | return 0; | ||
273 | } | ||
274 | |||
275 | /* Remove a single entry from the hash table given a pointer to that | ||
276 | ** element and a hash on the element's key. | ||
277 | */ | ||
278 | static void removeElementGivenHash( | ||
279 | Hash *pH, /* The pH containing "elem" */ | ||
280 | HashElem* elem, /* The element to be removed from the pH */ | ||
281 | int h /* Hash value for the element */ | ||
282 | ){ | ||
283 | struct _ht *pEntry; | ||
284 | if( elem->prev ){ | ||
285 | elem->prev->next = elem->next; | ||
286 | }else{ | ||
287 | pH->first = elem->next; | ||
288 | } | ||
289 | if( elem->next ){ | ||
290 | elem->next->prev = elem->prev; | ||
291 | } | ||
292 | pEntry = &pH->ht[h]; | ||
293 | if( pEntry->chain==elem ){ | ||
294 | pEntry->chain = elem->next; | ||
295 | } | ||
296 | pEntry->count--; | ||
297 | if( pEntry->count<=0 ){ | ||
298 | pEntry->chain = 0; | ||
299 | } | ||
300 | if( pH->copyKey ){ | ||
301 | sqlite3_free(elem->pKey); | ||
302 | } | ||
303 | sqlite3_free( elem ); | ||
304 | pH->count--; | ||
305 | if( pH->count<=0 ){ | ||
306 | assert( pH->first==0 ); | ||
307 | assert( pH->count==0 ); | ||
308 | sqlite3HashClear(pH); | ||
309 | } | ||
310 | } | ||
311 | |||
312 | /* Attempt to locate an element of the hash table pH with a key | ||
313 | ** that matches pKey,nKey. Return a pointer to the corresponding | ||
314 | ** HashElem structure for this element if it is found, or NULL | ||
315 | ** otherwise. | ||
316 | */ | ||
317 | HashElem *sqlite3HashFindElem(const Hash *pH, const void *pKey, int nKey){ | ||
318 | int h; /* A hash on key */ | ||
319 | HashElem *elem; /* The element that matches key */ | ||
320 | int (*xHash)(const void*,int); /* The hash function */ | ||
321 | |||
322 | if( pH==0 || pH->ht==0 ) return 0; | ||
323 | xHash = hashFunction(pH->keyClass); | ||
324 | assert( xHash!=0 ); | ||
325 | h = (*xHash)(pKey,nKey); | ||
326 | assert( (pH->htsize & (pH->htsize-1))==0 ); | ||
327 | elem = findElementGivenHash(pH,pKey,nKey, h & (pH->htsize-1)); | ||
328 | return elem; | ||
329 | } | ||
330 | |||
331 | /* Attempt to locate an element of the hash table pH with a key | ||
332 | ** that matches pKey,nKey. Return the data for this element if it is | ||
333 | ** found, or NULL if there is no match. | ||
334 | */ | ||
335 | void *sqlite3HashFind(const Hash *pH, const void *pKey, int nKey){ | ||
336 | HashElem *elem; /* The element that matches key */ | ||
337 | elem = sqlite3HashFindElem(pH, pKey, nKey); | ||
338 | return elem ? elem->data : 0; | ||
339 | } | ||
340 | |||
341 | /* Insert an element into the hash table pH. The key is pKey,nKey | ||
342 | ** and the data is "data". | ||
343 | ** | ||
344 | ** If no element exists with a matching key, then a new | ||
345 | ** element is created. A copy of the key is made if the copyKey | ||
346 | ** flag is set. NULL is returned. | ||
347 | ** | ||
348 | ** If another element already exists with the same key, then the | ||
349 | ** new data replaces the old data and the old data is returned. | ||
350 | ** The key is not copied in this instance. If a malloc fails, then | ||
351 | ** the new data is returned and the hash table is unchanged. | ||
352 | ** | ||
353 | ** If the "data" parameter to this function is NULL, then the | ||
354 | ** element corresponding to "key" is removed from the hash table. | ||
355 | */ | ||
356 | void *sqlite3HashInsert(Hash *pH, const void *pKey, int nKey, void *data){ | ||
357 | int hraw; /* Raw hash value of the key */ | ||
358 | int h; /* the hash of the key modulo hash table size */ | ||
359 | HashElem *elem; /* Used to loop thru the element list */ | ||
360 | HashElem *new_elem; /* New element added to the pH */ | ||
361 | int (*xHash)(const void*,int); /* The hash function */ | ||
362 | |||
363 | assert( pH!=0 ); | ||
364 | xHash = hashFunction(pH->keyClass); | ||
365 | assert( xHash!=0 ); | ||
366 | hraw = (*xHash)(pKey, nKey); | ||
367 | assert( (pH->htsize & (pH->htsize-1))==0 ); | ||
368 | h = hraw & (pH->htsize-1); | ||
369 | elem = findElementGivenHash(pH,pKey,nKey,h); | ||
370 | if( elem ){ | ||
371 | void *old_data = elem->data; | ||
372 | if( data==0 ){ | ||
373 | removeElementGivenHash(pH,elem,h); | ||
374 | }else{ | ||
375 | elem->data = data; | ||
376 | if( !pH->copyKey ){ | ||
377 | elem->pKey = (void *)pKey; | ||
378 | } | ||
379 | assert(nKey==elem->nKey); | ||
380 | } | ||
381 | return old_data; | ||
382 | } | ||
383 | if( data==0 ) return 0; | ||
384 | new_elem = (HashElem*)sqlite3_malloc( sizeof(HashElem) ); | ||
385 | if( new_elem==0 ) return data; | ||
386 | if( pH->copyKey && pKey!=0 ){ | ||
387 | new_elem->pKey = sqlite3_malloc( nKey ); | ||
388 | if( new_elem->pKey==0 ){ | ||
389 | sqlite3_free(new_elem); | ||
390 | return data; | ||
391 | } | ||
392 | memcpy((void*)new_elem->pKey, pKey, nKey); | ||
393 | }else{ | ||
394 | new_elem->pKey = (void*)pKey; | ||
395 | } | ||
396 | new_elem->nKey = nKey; | ||
397 | pH->count++; | ||
398 | if( pH->htsize==0 ){ | ||
399 | rehash(pH,8); | ||
400 | if( pH->htsize==0 ){ | ||
401 | pH->count = 0; | ||
402 | if( pH->copyKey ){ | ||
403 | sqlite3_free(new_elem->pKey); | ||
404 | } | ||
405 | sqlite3_free(new_elem); | ||
406 | return data; | ||
407 | } | ||
408 | } | ||
409 | if( pH->count > pH->htsize ){ | ||
410 | rehash(pH,pH->htsize*2); | ||
411 | } | ||
412 | assert( pH->htsize>0 ); | ||
413 | assert( (pH->htsize & (pH->htsize-1))==0 ); | ||
414 | h = hraw & (pH->htsize-1); | ||
415 | insertElement(pH, &pH->ht[h], new_elem); | ||
416 | new_elem->data = data; | ||
417 | return 0; | ||
418 | } | ||