File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / sqlite3 / ext / fts3 / fts3_hash.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 17:04:17 2012 UTC (12 years, 4 months ago) by misho
Branches: sqlite3, MAIN
CVS tags: v3_7_10, HEAD
sqlite3

    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 used in SQLite.
   13: ** We've modified it slightly to serve as a standalone hash table
   14: ** implementation for the full-text indexing module.
   15: */
   16: 
   17: /*
   18: ** The code in this file is only compiled if:
   19: **
   20: **     * The FTS3 module is being built as an extension
   21: **       (in which case SQLITE_CORE is not defined), or
   22: **
   23: **     * The FTS3 module is being built into the core of
   24: **       SQLite (in which case SQLITE_ENABLE_FTS3 is defined).
   25: */
   26: #include "fts3Int.h"
   27: #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3)
   28: 
   29: #include <assert.h>
   30: #include <stdlib.h>
   31: #include <string.h>
   32: 
   33: #include "fts3_hash.h"
   34: 
   35: /*
   36: ** Malloc and Free functions
   37: */
   38: static void *fts3HashMalloc(int n){
   39:   void *p = sqlite3_malloc(n);
   40:   if( p ){
   41:     memset(p, 0, n);
   42:   }
   43:   return p;
   44: }
   45: static void fts3HashFree(void *p){
   46:   sqlite3_free(p);
   47: }
   48: 
   49: /* Turn bulk memory into a hash table object by initializing the
   50: ** fields of the Hash structure.
   51: **
   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.
   58: */
   59: void sqlite3Fts3HashInit(Fts3Hash *pNew, char keyClass, char copyKey){
   60:   assert( pNew!=0 );
   61:   assert( keyClass>=FTS3_HASH_STRING && keyClass<=FTS3_HASH_BINARY );
   62:   pNew->keyClass = keyClass;
   63:   pNew->copyKey = copyKey;
   64:   pNew->first = 0;
   65:   pNew->count = 0;
   66:   pNew->htsize = 0;
   67:   pNew->ht = 0;
   68: }
   69: 
   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.
   73: */
   74: void sqlite3Fts3HashClear(Fts3Hash *pH){
   75:   Fts3HashElem *elem;         /* For looping over all elements of the table */
   76: 
   77:   assert( pH!=0 );
   78:   elem = pH->first;
   79:   pH->first = 0;
   80:   fts3HashFree(pH->ht);
   81:   pH->ht = 0;
   82:   pH->htsize = 0;
   83:   while( elem ){
   84:     Fts3HashElem *next_elem = elem->next;
   85:     if( pH->copyKey && elem->pKey ){
   86:       fts3HashFree(elem->pKey);
   87:     }
   88:     fts3HashFree(elem);
   89:     elem = next_elem;
   90:   }
   91:   pH->count = 0;
   92: }
   93: 
   94: /*
   95: ** Hash and comparison functions when the mode is FTS3_HASH_STRING
   96: */
   97: static int fts3StrHash(const void *pKey, int nKey){
   98:   const char *z = (const char *)pKey;
   99:   int h = 0;
  100:   if( nKey<=0 ) nKey = (int) strlen(z);
  101:   while( nKey > 0  ){
  102:     h = (h<<3) ^ h ^ *z++;
  103:     nKey--;
  104:   }
  105:   return h & 0x7fffffff;
  106: }
  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);
  110: }
  111: 
  112: /*
  113: ** Hash and comparison functions when the mode is FTS3_HASH_BINARY
  114: */
  115: static int fts3BinHash(const void *pKey, int nKey){
  116:   int h = 0;
  117:   const char *z = (const char *)pKey;
  118:   while( nKey-- > 0 ){
  119:     h = (h<<3) ^ h ^ *(z++);
  120:   }
  121:   return h & 0x7fffffff;
  122: }
  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);
  126: }
  127: 
  128: /*
  129: ** Return a pointer to the appropriate hash function given the key class.
  130: **
  131: ** The C syntax in this function definition may be unfamilar to some 
  132: ** programmers, so we provide the following additional explanation:
  133: **
  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".
  139: */
  140: static int (*ftsHashFunction(int keyClass))(const void*,int){
  141:   if( keyClass==FTS3_HASH_STRING ){
  142:     return &fts3StrHash;
  143:   }else{
  144:     assert( keyClass==FTS3_HASH_BINARY );
  145:     return &fts3BinHash;
  146:   }
  147: }
  148: 
  149: /*
  150: ** Return a pointer to the appropriate hash function given the key class.
  151: **
  152: ** For help in interpreted the obscure C code in the function definition,
  153: ** see the header comment on the previous function.
  154: */
  155: static int (*ftsCompareFunction(int keyClass))(const void*,int,const void*,int){
  156:   if( keyClass==FTS3_HASH_STRING ){
  157:     return &fts3StrCompare;
  158:   }else{
  159:     assert( keyClass==FTS3_HASH_BINARY );
  160:     return &fts3BinCompare;
  161:   }
  162: }
  163: 
  164: /* Link an element into the hash table
  165: */
  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 */
  170: ){
  171:   Fts3HashElem *pHead;     /* First element already in pEntry */
  172:   pHead = pEntry->chain;
  173:   if( pHead ){
  174:     pNew->next = pHead;
  175:     pNew->prev = pHead->prev;
  176:     if( pHead->prev ){ pHead->prev->next = pNew; }
  177:     else             { pH->first = pNew; }
  178:     pHead->prev = pNew;
  179:   }else{
  180:     pNew->next = pH->first;
  181:     if( pH->first ){ pH->first->prev = pNew; }
  182:     pNew->prev = 0;
  183:     pH->first = pNew;
  184:   }
  185:   pEntry->count++;
  186:   pEntry->chain = pNew;
  187: }
  188: 
  189: 
  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.
  193: **
  194: ** Return non-zero if a memory allocation error occurs.
  195: */
  196: static int fts3Rehash(Fts3Hash *pH, int new_size){
  197:   struct _fts3ht *new_ht;          /* The new hash table */
  198:   Fts3HashElem *elem, *next_elem;  /* For looping over existing elements */
  199:   int (*xHash)(const void*,int);   /* The hash function */
  200: 
  201:   assert( (new_size & (new_size-1))==0 );
  202:   new_ht = (struct _fts3ht *)fts3HashMalloc( new_size*sizeof(struct _fts3ht) );
  203:   if( new_ht==0 ) return 1;
  204:   fts3HashFree(pH->ht);
  205:   pH->ht = new_ht;
  206:   pH->htsize = new_size;
  207:   xHash = ftsHashFunction(pH->keyClass);
  208:   for(elem=pH->first, pH->first=0; elem; elem = next_elem){
  209:     int h = (*xHash)(elem->pKey, elem->nKey) & (new_size-1);
  210:     next_elem = elem->next;
  211:     fts3HashInsertElement(pH, &new_ht[h], elem);
  212:   }
  213:   return 0;
  214: }
  215: 
  216: /* This function (for internal use only) locates an element in an
  217: ** hash table that matches the given key.  The hash for this key has
  218: ** already been computed and is passed as the 4th parameter.
  219: */
  220: static Fts3HashElem *fts3FindElementByHash(
  221:   const Fts3Hash *pH, /* The pH to be searched */
  222:   const void *pKey,   /* The key we are searching for */
  223:   int nKey,
  224:   int h               /* The hash for this key. */
  225: ){
  226:   Fts3HashElem *elem;            /* Used to loop thru the element list */
  227:   int count;                     /* Number of elements left to test */
  228:   int (*xCompare)(const void*,int,const void*,int);  /* comparison function */
  229: 
  230:   if( pH->ht ){
  231:     struct _fts3ht *pEntry = &pH->ht[h];
  232:     elem = pEntry->chain;
  233:     count = pEntry->count;
  234:     xCompare = ftsCompareFunction(pH->keyClass);
  235:     while( count-- && elem ){
  236:       if( (*xCompare)(elem->pKey,elem->nKey,pKey,nKey)==0 ){ 
  237:         return elem;
  238:       }
  239:       elem = elem->next;
  240:     }
  241:   }
  242:   return 0;
  243: }
  244: 
  245: /* Remove a single entry from the hash table given a pointer to that
  246: ** element and a hash on the element's key.
  247: */
  248: static void fts3RemoveElementByHash(
  249:   Fts3Hash *pH,         /* The pH containing "elem" */
  250:   Fts3HashElem* elem,   /* The element to be removed from the pH */
  251:   int h                 /* Hash value for the element */
  252: ){
  253:   struct _fts3ht *pEntry;
  254:   if( elem->prev ){
  255:     elem->prev->next = elem->next; 
  256:   }else{
  257:     pH->first = elem->next;
  258:   }
  259:   if( elem->next ){
  260:     elem->next->prev = elem->prev;
  261:   }
  262:   pEntry = &pH->ht[h];
  263:   if( pEntry->chain==elem ){
  264:     pEntry->chain = elem->next;
  265:   }
  266:   pEntry->count--;
  267:   if( pEntry->count<=0 ){
  268:     pEntry->chain = 0;
  269:   }
  270:   if( pH->copyKey && elem->pKey ){
  271:     fts3HashFree(elem->pKey);
  272:   }
  273:   fts3HashFree( elem );
  274:   pH->count--;
  275:   if( pH->count<=0 ){
  276:     assert( pH->first==0 );
  277:     assert( pH->count==0 );
  278:     fts3HashClear(pH);
  279:   }
  280: }
  281: 
  282: Fts3HashElem *sqlite3Fts3HashFindElem(
  283:   const Fts3Hash *pH, 
  284:   const void *pKey, 
  285:   int nKey
  286: ){
  287:   int h;                          /* A hash on key */
  288:   int (*xHash)(const void*,int);  /* The hash function */
  289: 
  290:   if( pH==0 || pH->ht==0 ) return 0;
  291:   xHash = ftsHashFunction(pH->keyClass);
  292:   assert( xHash!=0 );
  293:   h = (*xHash)(pKey,nKey);
  294:   assert( (pH->htsize & (pH->htsize-1))==0 );
  295:   return fts3FindElementByHash(pH,pKey,nKey, h & (pH->htsize-1));
  296: }
  297: 
  298: /* 
  299: ** Attempt to locate an element of the hash table pH with a key
  300: ** that matches pKey,nKey.  Return the data for this element if it is
  301: ** found, or NULL if there is no match.
  302: */
  303: void *sqlite3Fts3HashFind(const Fts3Hash *pH, const void *pKey, int nKey){
  304:   Fts3HashElem *pElem;            /* The element that matches key (if any) */
  305: 
  306:   pElem = sqlite3Fts3HashFindElem(pH, pKey, nKey);
  307:   return pElem ? pElem->data : 0;
  308: }
  309: 
  310: /* Insert an element into the hash table pH.  The key is pKey,nKey
  311: ** and the data is "data".
  312: **
  313: ** If no element exists with a matching key, then a new
  314: ** element is created.  A copy of the key is made if the copyKey
  315: ** flag is set.  NULL is returned.
  316: **
  317: ** If another element already exists with the same key, then the
  318: ** new data replaces the old data and the old data is returned.
  319: ** The key is not copied in this instance.  If a malloc fails, then
  320: ** the new data is returned and the hash table is unchanged.
  321: **
  322: ** If the "data" parameter to this function is NULL, then the
  323: ** element corresponding to "key" is removed from the hash table.
  324: */
  325: void *sqlite3Fts3HashInsert(
  326:   Fts3Hash *pH,        /* The hash table to insert into */
  327:   const void *pKey,    /* The key */
  328:   int nKey,            /* Number of bytes in the key */
  329:   void *data           /* The data */
  330: ){
  331:   int hraw;                 /* Raw hash value of the key */
  332:   int h;                    /* the hash of the key modulo hash table size */
  333:   Fts3HashElem *elem;       /* Used to loop thru the element list */
  334:   Fts3HashElem *new_elem;   /* New element added to the pH */
  335:   int (*xHash)(const void*,int);  /* The hash function */
  336: 
  337:   assert( pH!=0 );
  338:   xHash = ftsHashFunction(pH->keyClass);
  339:   assert( xHash!=0 );
  340:   hraw = (*xHash)(pKey, nKey);
  341:   assert( (pH->htsize & (pH->htsize-1))==0 );
  342:   h = hraw & (pH->htsize-1);
  343:   elem = fts3FindElementByHash(pH,pKey,nKey,h);
  344:   if( elem ){
  345:     void *old_data = elem->data;
  346:     if( data==0 ){
  347:       fts3RemoveElementByHash(pH,elem,h);
  348:     }else{
  349:       elem->data = data;
  350:     }
  351:     return old_data;
  352:   }
  353:   if( data==0 ) return 0;
  354:   if( (pH->htsize==0 && fts3Rehash(pH,8))
  355:    || (pH->count>=pH->htsize && fts3Rehash(pH, pH->htsize*2))
  356:   ){
  357:     pH->count = 0;
  358:     return data;
  359:   }
  360:   assert( pH->htsize>0 );
  361:   new_elem = (Fts3HashElem*)fts3HashMalloc( sizeof(Fts3HashElem) );
  362:   if( new_elem==0 ) return data;
  363:   if( pH->copyKey && pKey!=0 ){
  364:     new_elem->pKey = fts3HashMalloc( nKey );
  365:     if( new_elem->pKey==0 ){
  366:       fts3HashFree(new_elem);
  367:       return data;
  368:     }
  369:     memcpy((void*)new_elem->pKey, pKey, nKey);
  370:   }else{
  371:     new_elem->pKey = (void*)pKey;
  372:   }
  373:   new_elem->nKey = nKey;
  374:   pH->count++;
  375:   assert( pH->htsize>0 );
  376:   assert( (pH->htsize & (pH->htsize-1))==0 );
  377:   h = hraw & (pH->htsize-1);
  378:   fts3HashInsertElement(pH, &pH->ht[h], new_elem);
  379:   new_elem->data = data;
  380:   return 0;
  381: }
  382: 
  383: #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>