4
** The author disclaims copyright to this source code. In place of
5
** a legal notice, here is a blessing:
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.
11
*************************************************************************
12
** This is the implementation of generic hash-tables used in SQLite.
13
** We've modified it slightly to serve as a standalone hash table
14
** implementation for the full-text indexing module.
18
** The code in this file is only compiled if:
20
** * The FTS3 module is being built as an extension
21
** (in which case SQLITE_CORE is not defined), or
23
** * The FTS3 module is being built into the core of
24
** SQLite (in which case SQLITE_ENABLE_FTS3 is defined).
26
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3)
33
#include "fts3_hash.h"
36
** Malloc and Free functions
38
static void *fts3HashMalloc(int n){
39
void *p = sqlite3_malloc(n);
45
static void fts3HashFree(void *p){
49
/* Turn bulk memory into a hash table object by initializing the
50
** fields of the Hash structure.
52
** "pNew" is a pointer to the hash table that is to be initialized.
53
** keyClass is one of the constants
54
** FTS3_HASH_BINARY or FTS3_HASH_STRING. The value of keyClass
55
** determines what kind of key the hash table will use. "copyKey" is
56
** true if the hash table should make its own private copy of keys and
57
** false if it should just use the supplied pointer.
59
void sqlite3Fts3HashInit(fts3Hash *pNew, int keyClass, int copyKey){
61
assert( keyClass>=FTS3_HASH_STRING && keyClass<=FTS3_HASH_BINARY );
62
pNew->keyClass = keyClass;
63
pNew->copyKey = copyKey;
70
/* Remove all entries from a hash table. Reclaim all memory.
71
** Call this routine to delete a hash table or to reset a hash table
72
** to the empty state.
74
void sqlite3Fts3HashClear(fts3Hash *pH){
75
fts3HashElem *elem; /* For looping over all elements of the table */
84
fts3HashElem *next_elem = elem->next;
85
if( pH->copyKey && elem->pKey ){
86
fts3HashFree(elem->pKey);
95
** Hash and comparison functions when the mode is FTS3_HASH_STRING
97
static int fts3StrHash(const void *pKey, int nKey){
98
const char *z = (const char *)pKey;
100
if( nKey<=0 ) nKey = (int) strlen(z);
102
h = (h<<3) ^ h ^ *z++;
105
return h & 0x7fffffff;
107
static int fts3StrCompare(const void *pKey1, int n1, const void *pKey2, int n2){
108
if( n1!=n2 ) return 1;
109
return strncmp((const char*)pKey1,(const char*)pKey2,n1);
113
** Hash and comparison functions when the mode is FTS3_HASH_BINARY
115
static int fts3BinHash(const void *pKey, int nKey){
117
const char *z = (const char *)pKey;
119
h = (h<<3) ^ h ^ *(z++);
121
return h & 0x7fffffff;
123
static int fts3BinCompare(const void *pKey1, int n1, const void *pKey2, int n2){
124
if( n1!=n2 ) return 1;
125
return memcmp(pKey1,pKey2,n1);
129
** Return a pointer to the appropriate hash function given the key class.
131
** The C syntax in this function definition may be unfamilar to some
132
** programmers, so we provide the following additional explanation:
134
** The name of the function is "ftsHashFunction". The function takes a
135
** single parameter "keyClass". The return value of ftsHashFunction()
136
** is a pointer to another function. Specifically, the return value
137
** of ftsHashFunction() is a pointer to a function that takes two parameters
138
** with types "const void*" and "int" and returns an "int".
140
static int (*ftsHashFunction(int keyClass))(const void*,int){
141
if( keyClass==FTS3_HASH_STRING ){
144
assert( keyClass==FTS3_HASH_BINARY );
150
** Return a pointer to the appropriate hash function given the key class.
152
** For help in interpreted the obscure C code in the function definition,
153
** see the header comment on the previous function.
155
static int (*ftsCompareFunction(int keyClass))(const void*,int,const void*,int){
156
if( keyClass==FTS3_HASH_STRING ){
157
return &fts3StrCompare;
159
assert( keyClass==FTS3_HASH_BINARY );
160
return &fts3BinCompare;
164
/* Link an element into the hash table
166
static void fts3HashInsertElement(
167
fts3Hash *pH, /* The complete hash table */
168
struct _fts3ht *pEntry, /* The entry into which pNew is inserted */
169
fts3HashElem *pNew /* The element to be inserted */
171
fts3HashElem *pHead; /* First element already in pEntry */
172
pHead = pEntry->chain;
175
pNew->prev = pHead->prev;
176
if( pHead->prev ){ pHead->prev->next = pNew; }
177
else { pH->first = pNew; }
180
pNew->next = pH->first;
181
if( pH->first ){ pH->first->prev = pNew; }
186
pEntry->chain = pNew;
190
/* Resize the hash table so that it cantains "new_size" buckets.
191
** "new_size" must be a power of 2. The hash table might fail
192
** to resize if sqliteMalloc() fails.
194
static void fts3Rehash(fts3Hash *pH, int new_size){
195
struct _fts3ht *new_ht; /* The new hash table */
196
fts3HashElem *elem, *next_elem; /* For looping over existing elements */
197
int (*xHash)(const void*,int); /* The hash function */
199
assert( (new_size & (new_size-1))==0 );
200
new_ht = (struct _fts3ht *)fts3HashMalloc( new_size*sizeof(struct _fts3ht) );
201
if( new_ht==0 ) return;
202
fts3HashFree(pH->ht);
204
pH->htsize = new_size;
205
xHash = ftsHashFunction(pH->keyClass);
206
for(elem=pH->first, pH->first=0; elem; elem = next_elem){
207
int h = (*xHash)(elem->pKey, elem->nKey) & (new_size-1);
208
next_elem = elem->next;
209
fts3HashInsertElement(pH, &new_ht[h], elem);
213
/* This function (for internal use only) locates an element in an
214
** hash table that matches the given key. The hash for this key has
215
** already been computed and is passed as the 4th parameter.
217
static fts3HashElem *fts3FindElementByHash(
218
const fts3Hash *pH, /* The pH to be searched */
219
const void *pKey, /* The key we are searching for */
221
int h /* The hash for this key. */
223
fts3HashElem *elem; /* Used to loop thru the element list */
224
int count; /* Number of elements left to test */
225
int (*xCompare)(const void*,int,const void*,int); /* comparison function */
228
struct _fts3ht *pEntry = &pH->ht[h];
229
elem = pEntry->chain;
230
count = pEntry->count;
231
xCompare = ftsCompareFunction(pH->keyClass);
232
while( count-- && elem ){
233
if( (*xCompare)(elem->pKey,elem->nKey,pKey,nKey)==0 ){
242
/* Remove a single entry from the hash table given a pointer to that
243
** element and a hash on the element's key.
245
static void fts3RemoveElementByHash(
246
fts3Hash *pH, /* The pH containing "elem" */
247
fts3HashElem* elem, /* The element to be removed from the pH */
248
int h /* Hash value for the element */
250
struct _fts3ht *pEntry;
252
elem->prev->next = elem->next;
254
pH->first = elem->next;
257
elem->next->prev = elem->prev;
260
if( pEntry->chain==elem ){
261
pEntry->chain = elem->next;
264
if( pEntry->count<=0 ){
267
if( pH->copyKey && elem->pKey ){
268
fts3HashFree(elem->pKey);
270
fts3HashFree( elem );
273
assert( pH->first==0 );
274
assert( pH->count==0 );
279
/* Attempt to locate an element of the hash table pH with a key
280
** that matches pKey,nKey. Return the data for this element if it is
281
** found, or NULL if there is no match.
283
void *sqlite3Fts3HashFind(const fts3Hash *pH, const void *pKey, int nKey){
284
int h; /* A hash on key */
285
fts3HashElem *elem; /* The element that matches key */
286
int (*xHash)(const void*,int); /* The hash function */
288
if( pH==0 || pH->ht==0 ) return 0;
289
xHash = ftsHashFunction(pH->keyClass);
291
h = (*xHash)(pKey,nKey);
292
assert( (pH->htsize & (pH->htsize-1))==0 );
293
elem = fts3FindElementByHash(pH,pKey,nKey, h & (pH->htsize-1));
294
return elem ? elem->data : 0;
297
/* Insert an element into the hash table pH. The key is pKey,nKey
298
** and the data is "data".
300
** If no element exists with a matching key, then a new
301
** element is created. A copy of the key is made if the copyKey
302
** flag is set. NULL is returned.
304
** If another element already exists with the same key, then the
305
** new data replaces the old data and the old data is returned.
306
** The key is not copied in this instance. If a malloc fails, then
307
** the new data is returned and the hash table is unchanged.
309
** If the "data" parameter to this function is NULL, then the
310
** element corresponding to "key" is removed from the hash table.
312
void *sqlite3Fts3HashInsert(
313
fts3Hash *pH, /* The hash table to insert into */
314
const void *pKey, /* The key */
315
int nKey, /* Number of bytes in the key */
316
void *data /* The data */
318
int hraw; /* Raw hash value of the key */
319
int h; /* the hash of the key modulo hash table size */
320
fts3HashElem *elem; /* Used to loop thru the element list */
321
fts3HashElem *new_elem; /* New element added to the pH */
322
int (*xHash)(const void*,int); /* The hash function */
325
xHash = ftsHashFunction(pH->keyClass);
327
hraw = (*xHash)(pKey, nKey);
328
assert( (pH->htsize & (pH->htsize-1))==0 );
329
h = hraw & (pH->htsize-1);
330
elem = fts3FindElementByHash(pH,pKey,nKey,h);
332
void *old_data = elem->data;
334
fts3RemoveElementByHash(pH,elem,h);
340
if( data==0 ) return 0;
341
new_elem = (fts3HashElem*)fts3HashMalloc( sizeof(fts3HashElem) );
342
if( new_elem==0 ) return data;
343
if( pH->copyKey && pKey!=0 ){
344
new_elem->pKey = fts3HashMalloc( nKey );
345
if( new_elem->pKey==0 ){
346
fts3HashFree(new_elem);
349
memcpy((void*)new_elem->pKey, pKey, nKey);
351
new_elem->pKey = (void*)pKey;
353
new_elem->nKey = nKey;
359
fts3HashFree(new_elem);
363
if( pH->count > pH->htsize ){
364
fts3Rehash(pH,pH->htsize*2);
366
assert( pH->htsize>0 );
367
assert( (pH->htsize & (pH->htsize-1))==0 );
368
h = hraw & (pH->htsize-1);
369
fts3HashInsertElement(pH, &pH->ht[h], new_elem);
370
new_elem->data = data;
374
#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */