hashtable.c
上传用户:ykyjsl
上传日期:2022-01-30
资源大小:145k
文件大小:10k
源码类别:

压缩解压

开发平台:

C/C++

  1. /******************************************************************************
  2. File:         hashtable.c
  3. Authors:  John Carpinelli   (johnfc@ecr.mu.oz.au)
  4.   Wayne Salamonsen  (wbs@mundil.cs.mu.oz.au)
  5. Purpose: Data compression using a word-based model and revised 
  6. arithmetic coding method.
  7. Based on:  A. Moffat, R. Neal, I.H. Witten, "Arithmetic Coding Revisted",
  8. Proc. IEEE Data Compression Conference, Snowbird, Utah, 
  9. March 1995.
  10. Copyright 1995 John Carpinelli and Wayne Salamonsen, All Rights Reserved.
  11. These programs are supplied free of charge for research purposes only,
  12. and may not sold or incorporated into any commercial product.  There is
  13. ABSOLUTELY NO WARRANTY of any sort, nor any undertaking that they are
  14. fit for ANY PURPOSE WHATSOEVER.  Use them at your own risk.  If you do
  15. happen to find a bug, or have modifications to suggest, please report
  16. the same to Alistair Moffat, alistair@cs.mu.oz.au.  The copyright
  17. notice above and this statement of conditions must remain an integral
  18. part of each and every copy made of these files.
  19.  $Log: hashtable.c,v $
  20.  Revision 1.1  1996/08/07 01:34:11  langs
  21.  Initial revision
  22. ******************************************************************************/
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <string.h>
  26. #include "arith.h"
  27. #include "stats.h"
  28. #include "main.h"
  29. #include "hashtable.h"
  30. #ifdef RCSID
  31. static char rcsid[] = "$Id: hashtable.c,v 1.1 1996/08/07 01:34:11 langs Exp $";
  32. #endif
  33. /* Local function declarations */
  34. static bucket *get_bucket(hash_table *pTable);
  35. static unsigned char *add_string(string *pItem, hash_table *pTable);
  36. /*
  37.  *
  38.  * Extendible hashing is used to store both words and non-words. The
  39.  * initial size of the hash table is determined by INITIAL_BITS.
  40.  *
  41.  * Converting word numbers to words in the decoder is done using an
  42.  * array of word pointers. Each hash table holds this array and updates
  43.  * it as words are added.
  44.  *
  45.  */
  46. /*
  47.  *
  48.  * create a new hash table
  49.  * returns pointer to new table, or NULL if memory exhausted
  50.  *
  51.  */
  52. hash_table 
  53. *create_table(void)
  54. {
  55.     hash_table *pTable;
  56.     /* allocate the hash table structure */
  57.     if ((pTable = (hash_table *) do_malloc(sizeof(hash_table))) == NULL)
  58. return NULL;
  59.     
  60.     /* initially allocate index of length one */
  61.     pTable->nBits = 0;
  62.     pTable->nBuckets = 0;
  63.     if ((pTable->pIndex = (bucket **) do_malloc(sizeof(bucket *))) == NULL)
  64. return NULL;
  65.     /* point index to first bucket */
  66.     pTable->pFreeBuckets = NULL;
  67.     pTable->pIndex[0] = get_bucket(pTable);
  68.     pTable->pIndex[0]->nBits = 0;
  69.     pTable->pIndex[0]->nWords = 0;
  70.     pTable->next_number = EXTRA_SYMBOLS;
  71.     /* start string tables */
  72.     if ((pTable->pStrings = (string_block *) do_malloc(sizeof(string_block)))
  73. == NULL)
  74. return NULL;
  75.     pTable->pStrings->prev = NULL;
  76.     pTable->pStrings->length = 0;
  77.     /* allocate memory for Number-to-Wordptr array */
  78.     if ((pTable->pNumToWords = (unsigned char **) 
  79. do_malloc(ALLOCATE_BLOCK * sizeof(unsigned char **))) == NULL)
  80. return NULL;
  81.     pTable->numToWordsLimit = ALLOCATE_BLOCK;
  82.     return pTable;
  83. }
  84. /*
  85.  *
  86.  * get an empty bucket from the pool of preallocated buckets
  87.  * returns NULL if memory exceeded
  88.  *
  89.  */
  90. static bucket *get_bucket(hash_table *pTable)
  91. {
  92.     bucket_block *pBlock, *pNew;
  93.     pBlock=pTable->pFreeBuckets;
  94.     
  95.     if ((pBlock == NULL) || (pBlock->nFreeBuckets == 0)) 
  96.     {
  97. if ((pNew=(bucket_block *) do_malloc(sizeof(bucket_block))) == NULL)
  98.     return NULL;
  99. pNew->prev = pBlock;
  100. pTable->pFreeBuckets = pNew;
  101. if ((pNew->pBuckets = (bucket *) 
  102.     do_malloc(sizeof(bucket) * ALLOCATE_BLOCK)) == NULL)
  103.     return NULL;
  104. pNew->nFreeBuckets = ALLOCATE_BLOCK;
  105. pBlock = pNew;
  106.      pNew->pBuckets->nBits = 0;
  107.         pNew->pBuckets->nWords = 0;
  108.     }
  109.     pTable->nBuckets++;
  110.     pBlock->nFreeBuckets--;
  111.     return (pBlock->pBuckets + pBlock->nFreeBuckets);
  112. }
  113. /*
  114.  * 
  115.  * hash function which takes a length and a pointer to the string
  116.  *
  117.  */
  118. int 
  119. hash(int length, unsigned char *pText)
  120. {
  121.     int hash, i;
  122.     hash = 0;
  123.     for (i = 0; i < length; i++) 
  124. hash = HASH_MULT*hash + pText[i];
  125.     hash += length;
  126.     hash = hash % HASH_MOD;
  127.     return hash;
  128. }
  129. /*
  130.  *
  131.  * look up a word in the hash table.
  132.  * Returns the ordinal word number if word found, 
  133.  * or the next unused word number if word is unknown
  134.  *
  135.  */
  136. int 
  137. lookup_word(string *pItem, hash_table *pTable)
  138. {
  139.     int i, key;
  140.     bucket *pBucket;
  141.     key = hash(pItem->length, pItem->text);
  142.     /* strip off the unused bits of the key */
  143.     key = key & ((1 << pTable->nBits) -1);
  144.     pBucket = pTable->pIndex[key];
  145.     /* search the bucket for the string */
  146.     for (i = 0; i<pBucket->nWords; i++)
  147.     {
  148. /* compare the lengths */
  149. if (pItem->length == (int) *(pBucket->words[i].pWord))
  150. {
  151.     /* compare the text */
  152.     if (memcmp(pItem->text,pBucket->words[i].pWord+1,
  153. pItem->length) == 0) 
  154. return pBucket->words[i].wordNumber;
  155. }
  156.     }
  157.     return pTable->next_number; /* return next available number */
  158. }
  159. /*
  160.  *
  161.  * add a word to the hash table
  162.  * if the bucket overflows, double the size of the table and split
  163.  * all buckets
  164.  * returns word number if successful, or NOMEMLEFT if memory limit reached
  165.  *
  166.  */
  167. int 
  168. add_word(string *pItem, hash_table *pTable)
  169. {
  170.     int i, key, tail, length, nWord, nWordsOld, nWordsNew, word_no;
  171.     bucket *pBucket, *pNewBucket;
  172.     /* note new memory required by statistics to store symbol */
  173.     if (get_memory(MEM_PER_SYMBOL) == NOMEMLEFT)
  174. return NOMEMLEFT;
  175.     key = hash(pItem->length, pItem->text);
  176.     /* strip off the unused bits of the key */
  177.     key = key & ((1 << pTable->nBits) -1);
  178.     pBucket = pTable->pIndex[key];
  179.     /* add the item to the bucket */
  180.     nWord = pBucket->nWords;
  181.     if (nWord < MAXBUCKET) 
  182.     {
  183. pBucket->words[nWord].wordNumber = (word_no = pTable->next_number);
  184. pTable->next_number++;
  185. if ((pBucket->words[nWord].pWord = add_string(pItem, pTable)) == NULL)
  186.     return NOMEMLEFT;
  187. pTable->pNumToWords[word_no-EXTRA_SYMBOLS] = 
  188.     pBucket->words[nWord].pWord;
  189. pBucket->nWords++;
  190.     }
  191.     else {
  192. /* split bucket on pBucket->nBits+1 bit */
  193. tail = key & ((1 << pBucket->nBits) -1); /* save for later */
  194. pBucket->nBits++;
  195. if ((pNewBucket = get_bucket(pTable))==NULL)
  196.     return NOMEMLEFT;
  197. pNewBucket->nBits = pBucket->nBits;
  198. nWordsOld = 0;
  199. nWordsNew = 0;
  200. for (nWord = 0; nWord < pBucket->nWords; nWord++) 
  201. {
  202.     /*
  203.      * move each word depending on the leftmost 
  204.      * significant bit
  205.      */
  206.     key = hash(*(pBucket->words[nWord].pWord),
  207.        (pBucket->words[nWord].pWord)+1);
  208.     key = key & (1 << (pBucket->nBits - 1));
  209.     if (key>0) 
  210.     { /* move word to new bucket */
  211. pNewBucket->words[nWordsNew] = pBucket->words[nWord];
  212. nWordsNew++;
  213.     }
  214.     else 
  215.     { /* put word in old bucket */
  216. pBucket->words[nWordsOld] = pBucket->words[nWord];
  217. nWordsOld++;
  218.     }
  219. }
  220. pNewBucket->nWords = nWordsNew;
  221. pBucket->nWords = nWordsOld;
  222. /* check if we need to double the index, or rearrange pointers */
  223. if (pBucket->nBits <= pTable->nBits) 
  224. {  
  225.     /* add leading one to key to make new bucket key */
  226.     tail = tail | (1 << (pBucket->nBits-1));
  227.     /* point index entries ending with tail to new bucket */
  228.     for (i=0; i < (1 << (pTable->nBits - pBucket->nBits)); i++)
  229. pTable->pIndex[(i << pBucket->nBits) | tail] = pNewBucket;
  230. }
  231. else
  232. {
  233.     /* must double size of table */
  234.     length = 1 << pTable->nBits;
  235.     pTable->nBits++;
  236.     if ((pTable->pIndex = (bucket **) 
  237.  do_realloc(pTable->pIndex, length * 2 * sizeof(bucket *)))
  238.   == NULL)
  239. return NOMEMLEFT;
  240.     
  241.     /* copy old half of index into new half */
  242.     memcpy(pTable->pIndex + length, pTable->pIndex, 
  243.    length*sizeof(bucket *));
  244.     
  245.     /* pointer in second half points to new bucket */
  246.     pTable->pIndex[(1 << (pTable->nBits-1)) | tail] = pNewBucket;
  247. }
  248. return (add_word(pItem, pTable));
  249.     }
  250.     if (pTable->next_number-EXTRA_SYMBOLS == pTable->numToWordsLimit)
  251.     {
  252. pTable->numToWordsLimit *= GROWTH_RATE;
  253. /* resize NumToWords array to new size */
  254. pTable->pNumToWords = (unsigned char **) 
  255.     do_realloc(pTable->pNumToWords, pTable->numToWordsLimit * 
  256.        sizeof(char *));
  257.      if (pTable->pNumToWords == NULL)
  258.     return NOMEMLEFT;
  259.     }
  260.     return word_no;
  261. }
  262. /*
  263. *
  264. * look up a word given its ordinal word number,
  265. * returning a pointer to the text and updating the length
  266. *
  267. */
  268. void 
  269. get_word(hash_table *pTable, int symbol, unsigned char **pText, int *pLength)
  270. {
  271.     *pText = pTable->pNumToWords[symbol-EXTRA_SYMBOLS];
  272.     *pLength = (int) *((unsigned char *)*pText);
  273.     *pText += 1; /* move pointer past length bytes */
  274. }
  275. /*
  276.  *
  277.  * function to add a string to a hash table's string block
  278.  * if the string_block is full, create a new one and link it to the old one
  279.  * returns a pointer to the string in the string block
  280.  * Returns NULL if memory limit exceeded
  281.  *
  282.  */
  283. static unsigned char 
  284. *add_string(string *pItem, hash_table *pTable)
  285. {
  286.     unsigned char *pWord;
  287.     string_block *pBlock, *pNew;
  288.     pBlock = pTable->pStrings;
  289.     /* check that there is enough room in the string block */
  290.     if (STRINGBLOCK - pBlock->length > pItem->length+1) 
  291.     {
  292. /* copy the length then the text into the string block */
  293. pWord = pBlock->strings+pBlock->length;
  294. *pWord = pItem->length;
  295. memcpy(pWord+1, pItem->text, pItem->length);
  296. pBlock->length += pItem->length+1;
  297. return (pWord);
  298.     }
  299.     else {
  300. if ((pNew = (string_block *) do_malloc(sizeof(string_block))) == NULL)
  301. {
  302. /* Reached memory limit adding new word */
  303.     return NULL;
  304. }
  305. pNew->prev = pBlock;
  306. pNew->length = 0;
  307. pTable->pStrings = pNew;
  308. return (add_string(pItem, pTable));
  309.     }
  310. }
  311. /*
  312. *
  313. * free all memory associated with a hash table
  314. *
  315. */
  316. void 
  317. purge_table(hash_table *pTable)
  318. {
  319.     string_block *pThis, *pPrev;
  320.     bucket_block *pBlock, *prev;
  321.     free(pTable->pNumToWords);
  322.     free(pTable->pIndex);
  323.     /* free the linked list of bucket blocks */
  324.     pBlock = pTable->pFreeBuckets;
  325.     while (pBlock != NULL)
  326.     {
  327. prev = pBlock->prev;
  328. free(pBlock);
  329. pBlock=prev;
  330.     }
  331.     /* free the linked list of string blocks */
  332.     pThis = pTable->pStrings;
  333.     while (pThis != NULL)
  334.     {
  335. pPrev = pThis->prev;
  336. free(pThis);
  337. pThis = pPrev;
  338.     }
  339.     free(pTable);
  340. }