15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** 2001 September 22
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** The author disclaims copyright to this source code.  In place of
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** a legal notice, here is a blessing:
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**    May you do good and not evil.
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**    May you find forgiveness for yourself and forgive others.
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**    May you share freely, never taking more than you give.
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*************************************************************************
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** This is the implementation of generic hash-tables used in SQLite.
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** We've modified it slightly to serve as a standalone hash table
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** implementation for the full-text indexing module.
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <assert.h>
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdlib.h>
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string.h>
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** The code in this file is only compiled if:
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**     * The FTS1 module is being built as an extension
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**       (in which case SQLITE_CORE is not defined), or
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**     * The FTS1 module is being built into the core of
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**       SQLite (in which case SQLITE_ENABLE_FTS1 is defined).
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS1)
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "fts1_hash.h"
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void *malloc_and_zero(int n){
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void *p = malloc(n);
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( p ){
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    memset(p, 0, n);
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return p;
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Turn bulk memory into a hash table object by initializing the
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** fields of the Hash structure.
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** "pNew" is a pointer to the hash table that is to be initialized.
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** keyClass is one of the constants
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** FTS1_HASH_BINARY or FTS1_HASH_STRING.  The value of keyClass
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** determines what kind of key the hash table will use.  "copyKey" is
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** true if the hash table should make its own private copy of keys and
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** false if it should just use the supplied pointer.
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void sqlite3Fts1HashInit(fts1Hash *pNew, int keyClass, int copyKey){
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( pNew!=0 );
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( keyClass>=FTS1_HASH_STRING && keyClass<=FTS1_HASH_BINARY );
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pNew->keyClass = keyClass;
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pNew->copyKey = copyKey;
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pNew->first = 0;
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pNew->count = 0;
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pNew->htsize = 0;
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pNew->ht = 0;
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pNew->xMalloc = malloc_and_zero;
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pNew->xFree = free;
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Remove all entries from a hash table.  Reclaim all memory.
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Call this routine to delete a hash table or to reset a hash table
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** to the empty state.
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void sqlite3Fts1HashClear(fts1Hash *pH){
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fts1HashElem *elem;         /* For looping over all elements of the table */
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( pH!=0 );
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  elem = pH->first;
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pH->first = 0;
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( pH->ht ) pH->xFree(pH->ht);
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pH->ht = 0;
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pH->htsize = 0;
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while( elem ){
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    fts1HashElem *next_elem = elem->next;
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( pH->copyKey && elem->pKey ){
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pH->xFree(elem->pKey);
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pH->xFree(elem);
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elem = next_elem;
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pH->count = 0;
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Hash and comparison functions when the mode is FTS1_HASH_STRING
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int strHash(const void *pKey, int nKey){
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const char *z = (const char *)pKey;
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int h = 0;
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( nKey<=0 ) nKey = (int) strlen(z);
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while( nKey > 0  ){
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    h = (h<<3) ^ h ^ *z++;
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    nKey--;
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return h & 0x7fffffff;
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int strCompare(const void *pKey1, int n1, const void *pKey2, int n2){
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( n1!=n2 ) return 1;
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return strncmp((const char*)pKey1,(const char*)pKey2,n1);
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Hash and comparison functions when the mode is FTS1_HASH_BINARY
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int binHash(const void *pKey, int nKey){
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int h = 0;
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const char *z = (const char *)pKey;
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while( nKey-- > 0 ){
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    h = (h<<3) ^ h ^ *(z++);
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return h & 0x7fffffff;
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int binCompare(const void *pKey1, int n1, const void *pKey2, int n2){
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( n1!=n2 ) return 1;
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return memcmp(pKey1,pKey2,n1);
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Return a pointer to the appropriate hash function given the key class.
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** The C syntax in this function definition may be unfamilar to some
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** programmers, so we provide the following additional explanation:
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** The name of the function is "hashFunction".  The function takes a
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** single parameter "keyClass".  The return value of hashFunction()
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** is a pointer to another function.  Specifically, the return value
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** of hashFunction() is a pointer to a function that takes two parameters
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** with types "const void*" and "int" and returns an "int".
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int (*hashFunction(int keyClass))(const void*,int){
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( keyClass==FTS1_HASH_STRING ){
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return &strHash;
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }else{
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    assert( keyClass==FTS1_HASH_BINARY );
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return &binHash;
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Return a pointer to the appropriate hash function given the key class.
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** For help in interpreted the obscure C code in the function definition,
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** see the header comment on the previous function.
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int (*compareFunction(int keyClass))(const void*,int,const void*,int){
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( keyClass==FTS1_HASH_STRING ){
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return &strCompare;
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }else{
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    assert( keyClass==FTS1_HASH_BINARY );
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return &binCompare;
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Link an element into the hash table
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void insertElement(
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fts1Hash *pH,            /* The complete hash table */
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct _fts1ht *pEntry,  /* The entry into which pNew is inserted */
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fts1HashElem *pNew       /* The element to be inserted */
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)){
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fts1HashElem *pHead;     /* First element already in pEntry */
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pHead = pEntry->chain;
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( pHead ){
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pNew->next = pHead;
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pNew->prev = pHead->prev;
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( pHead->prev ){ pHead->prev->next = pNew; }
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else             { pH->first = pNew; }
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pHead->prev = pNew;
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }else{
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pNew->next = pH->first;
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( pH->first ){ pH->first->prev = pNew; }
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pNew->prev = 0;
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pH->first = pNew;
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pEntry->count++;
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pEntry->chain = pNew;
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Resize the hash table so that it cantains "new_size" buckets.
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** "new_size" must be a power of 2.  The hash table might fail
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** to resize if sqliteMalloc() fails.
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void rehash(fts1Hash *pH, int new_size){
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct _fts1ht *new_ht;          /* The new hash table */
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fts1HashElem *elem, *next_elem;  /* For looping over existing elements */
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int (*xHash)(const void*,int);   /* The hash function */
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( (new_size & (new_size-1))==0 );
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  new_ht = (struct _fts1ht *)pH->xMalloc( new_size*sizeof(struct _fts1ht) );
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( new_ht==0 ) return;
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( pH->ht ) pH->xFree(pH->ht);
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pH->ht = new_ht;
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pH->htsize = new_size;
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  xHash = hashFunction(pH->keyClass);
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for(elem=pH->first, pH->first=0; elem; elem = next_elem){
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int h = (*xHash)(elem->pKey, elem->nKey) & (new_size-1);
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    next_elem = elem->next;
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    insertElement(pH, &new_ht[h], elem);
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* This function (for internal use only) locates an element in an
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** hash table that matches the given key.  The hash for this key has
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** already been computed and is passed as the 4th parameter.
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static fts1HashElem *findElementGivenHash(
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const fts1Hash *pH, /* The pH to be searched */
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const void *pKey,   /* The key we are searching for */
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int nKey,
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int h               /* The hash for this key. */
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)){
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fts1HashElem *elem;            /* Used to loop thru the element list */
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int count;                     /* Number of elements left to test */
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int (*xCompare)(const void*,int,const void*,int);  /* comparison function */
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( pH->ht ){
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    struct _fts1ht *pEntry = &pH->ht[h];
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elem = pEntry->chain;
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    count = pEntry->count;
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    xCompare = compareFunction(pH->keyClass);
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    while( count-- && elem ){
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if( (*xCompare)(elem->pKey,elem->nKey,pKey,nKey)==0 ){
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return elem;
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      elem = elem->next;
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return 0;
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Remove a single entry from the hash table given a pointer to that
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** element and a hash on the element's key.
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void removeElementGivenHash(
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fts1Hash *pH,         /* The pH containing "elem" */
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fts1HashElem* elem,   /* The element to be removed from the pH */
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int h                 /* Hash value for the element */
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)){
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct _fts1ht *pEntry;
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( elem->prev ){
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elem->prev->next = elem->next;
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }else{
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pH->first = elem->next;
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( elem->next ){
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elem->next->prev = elem->prev;
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pEntry = &pH->ht[h];
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( pEntry->chain==elem ){
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pEntry->chain = elem->next;
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pEntry->count--;
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( pEntry->count<=0 ){
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pEntry->chain = 0;
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( pH->copyKey && elem->pKey ){
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pH->xFree(elem->pKey);
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pH->xFree( elem );
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pH->count--;
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( pH->count<=0 ){
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    assert( pH->first==0 );
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    assert( pH->count==0 );
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    fts1HashClear(pH);
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Attempt to locate an element of the hash table pH with a key
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** that matches pKey,nKey.  Return the data for this element if it is
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** found, or NULL if there is no match.
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void *sqlite3Fts1HashFind(const fts1Hash *pH, const void *pKey, int nKey){
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int h;                 /* A hash on key */
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fts1HashElem *elem;    /* The element that matches key */
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int (*xHash)(const void*,int);  /* The hash function */
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( pH==0 || pH->ht==0 ) return 0;
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  xHash = hashFunction(pH->keyClass);
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( xHash!=0 );
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  h = (*xHash)(pKey,nKey);
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( (pH->htsize & (pH->htsize-1))==0 );
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  elem = findElementGivenHash(pH,pKey,nKey, h & (pH->htsize-1));
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return elem ? elem->data : 0;
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Insert an element into the hash table pH.  The key is pKey,nKey
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** and the data is "data".
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** If no element exists with a matching key, then a new
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** element is created.  A copy of the key is made if the copyKey
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** flag is set.  NULL is returned.
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** If another element already exists with the same key, then the
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** new data replaces the old data and the old data is returned.
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** The key is not copied in this instance.  If a malloc fails, then
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** the new data is returned and the hash table is unchanged.
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** If the "data" parameter to this function is NULL, then the
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** element corresponding to "key" is removed from the hash table.
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void *sqlite3Fts1HashInsert(
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fts1Hash *pH,        /* The hash table to insert into */
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const void *pKey,    /* The key */
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int nKey,            /* Number of bytes in the key */
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void *data           /* The data */
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)){
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int hraw;                 /* Raw hash value of the key */
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int h;                    /* the hash of the key modulo hash table size */
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fts1HashElem *elem;       /* Used to loop thru the element list */
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fts1HashElem *new_elem;   /* New element added to the pH */
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int (*xHash)(const void*,int);  /* The hash function */
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( pH!=0 );
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  xHash = hashFunction(pH->keyClass);
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( xHash!=0 );
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  hraw = (*xHash)(pKey, nKey);
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( (pH->htsize & (pH->htsize-1))==0 );
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  h = hraw & (pH->htsize-1);
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  elem = findElementGivenHash(pH,pKey,nKey,h);
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( elem ){
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    void *old_data = elem->data;
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( data==0 ){
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      removeElementGivenHash(pH,elem,h);
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }else{
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      elem->data = data;
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return old_data;
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( data==0 ) return 0;
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  new_elem = (fts1HashElem*)pH->xMalloc( sizeof(fts1HashElem) );
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( new_elem==0 ) return data;
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( pH->copyKey && pKey!=0 ){
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    new_elem->pKey = pH->xMalloc( nKey );
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( new_elem->pKey==0 ){
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pH->xFree(new_elem);
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return data;
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    memcpy((void*)new_elem->pKey, pKey, nKey);
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }else{
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    new_elem->pKey = (void*)pKey;
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  new_elem->nKey = nKey;
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pH->count++;
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( pH->htsize==0 ){
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    rehash(pH,8);
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( pH->htsize==0 ){
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pH->count = 0;
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pH->xFree(new_elem);
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return data;
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( pH->count > pH->htsize ){
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    rehash(pH,pH->htsize*2);
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( pH->htsize>0 );
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( (pH->htsize & (pH->htsize-1))==0 );
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  h = hraw & (pH->htsize-1);
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  insertElement(pH, &pH->ht[h], new_elem);
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  new_elem->data = data;
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return 0;
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS1) */
370