Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

286 lines
6.5 KiB

  1. /*
  2. * @doc INTERNAL
  3. *
  4. * @module HASH.C -- RTF control word cache |
  5. * #ifdef'ed with RTF_HASHCACHE
  6. *
  7. * Owner: <nl>
  8. * Jon Matousek <nl>
  9. *
  10. * History: <nl>
  11. * 8/15/95 jonmat first hash-cache for RTF using Brent's Method.
  12. */
  13. #include "_common.h"
  14. #ifdef RTF_HASHCACHE
  15. #include "hash.h"
  16. ASSERTDATA
  17. extern KEYWORD rgKeyword[]; // All of the RTF control words.
  18. #define MAX_INAME 3
  19. typedef struct {
  20. const KEYWORD *token;
  21. BOOL passBit;
  22. } HashEntry;
  23. static HashEntry *(hashtbl[HASHSIZE]);
  24. static HashEntry *storage; // Dynamically alloc for cKeywords.
  25. BOOL _rtfHashInited = FALSE;
  26. static INT HashKeyword_Key( const CHAR *szKeyword );
  27. /*
  28. * HashKeyword_Insert()
  29. *
  30. * @func
  31. * Insert a KEYWORD into the RTF hash table.
  32. * @comm
  33. * This function uses the the % for MOD
  34. * in order to validate MOD257.
  35. */
  36. VOID HashKeyword_Insert (
  37. const KEYWORD *token )//@parm pointer to KEYWORD token to insert.
  38. {
  39. TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "HashKeyword_Insert");
  40. INT index, step, position,
  41. cost, source, sink, index1,
  42. step1, temp;
  43. BOOL tmpPassBit;
  44. static INT totalKeys = 0;
  45. CHAR *szKeyword;
  46. HashEntry *np;
  47. AssertSz ( _rtfHashInited, "forgot to call HashKeyword_Init()");
  48. AssertSz ( totalKeys <= HASHSIZE * 0.7, "prime not large enough to hold total keys");
  49. szKeyword = token->szKeyword;
  50. np = &storage[totalKeys++];
  51. np->token = token;
  52. index = HashKeyword_Key(szKeyword) % HASHSIZE; // Get keys.
  53. step = 1 + (HashKeyword_Key(szKeyword) % (HASHSIZE-1));
  54. position = 1;
  55. cost = HASHSIZE; // The max collisions for any.
  56. while(hashtbl[index]!=NULL) // Find empty slot.
  57. {
  58. position++; // How many collisions.
  59. // For the keyword stored here, calc # times before it is found.
  60. temp=1;
  61. step1= 1+(HashKeyword_Key(hashtbl[index]->token->szKeyword) % (HASHSIZE-1));
  62. index1= (index+step1)%HASHSIZE;
  63. while(hashtbl[index1] !=NULL)
  64. {
  65. index1=(index1+step1)%HASHSIZE;
  66. temp++;
  67. }
  68. // Incremental cost computation, minimizes average # of collisions
  69. // for both keywords.
  70. if (cost>position+temp)
  71. {
  72. source=index;
  73. sink=index1;
  74. cost=position+temp;
  75. }
  76. // There will be something stored beyound here, set the passBit.
  77. hashtbl[index]->passBit=1;
  78. // Next index to search for empty slot.
  79. index=(index+step)%HASHSIZE;
  80. }
  81. if (position<=cost)
  82. {
  83. source=sink=index;
  84. cost=position;
  85. }
  86. hashtbl[sink] = hashtbl[source];
  87. hashtbl[source] = np;
  88. if (hashtbl[sink] && hashtbl[source]) // jOn hack, we didn't really
  89. { // want to swap pass bits.
  90. tmpPassBit = hashtbl[sink]->passBit;
  91. hashtbl[sink]->passBit = hashtbl[source]->passBit;
  92. hashtbl[source]->passBit = tmpPassBit;
  93. }
  94. }
  95. /*
  96. * static HashKeyword_Key()
  97. *
  98. * @func
  99. * Calculate the hash key.
  100. * @comm
  101. * Just add up the first few characters.
  102. * @rdesc
  103. * The hash Key for calculating the index and step.
  104. */
  105. static INT HashKeyword_Key(
  106. const CHAR *szKeyword ) //@parm C string to create hash key for.
  107. {
  108. TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "HashKeyword_Key");
  109. INT i, tot = 0;
  110. /* Just add up first few characters. */
  111. for (i = 0; i < MAX_INAME && *szKeyword; szKeyword++, i++)
  112. tot += (UCHAR) *szKeyword;
  113. return tot;
  114. }
  115. /*
  116. * HashKeyword_Fetch()
  117. *
  118. * @func
  119. * Look up a KEYWORD with the given szKeyword.
  120. * @devnote
  121. * We have a hash table of size 257. This allows for
  122. * the use of very fast routines to calculate a MOD 257.
  123. * This gives us a significant increase in performance
  124. * over a binary search.
  125. * @rdesc
  126. * A pointer to the KEYWORD, or NULL if not found.
  127. */
  128. const KEYWORD *HashKeyword_Fetch (
  129. const CHAR *szKeyword ) //@parm C string to search for.
  130. {
  131. TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "HashKeyword_Fetch");
  132. INT index, step;
  133. HashEntry * hashTblPtr;
  134. BYTE * pchCandidate;
  135. BYTE * pchKeyword;
  136. INT nComp;
  137. CHAR firstChar;
  138. INT hashKey;
  139. AssertSz( HASHSIZE == 257, "Remove custom MOD257.");
  140. firstChar = *szKeyword;
  141. hashKey = HashKeyword_Key(szKeyword); // For calc'ing 'index' and 'step'
  142. //index = hashKey%HASHSIZE; // First entry to search.
  143. index = MOD257(hashKey); // This formula gives us 18% perf.
  144. hashTblPtr = hashtbl[index]; // Get first entry.
  145. if ( hashTblPtr != NULL ) // Something there?
  146. {
  147. // Compare 2 C strings.
  148. pchCandidate = (BYTE *)hashTblPtr->token->szKeyword;
  149. if ( firstChar == *pchCandidate )
  150. {
  151. pchKeyword = (BYTE *)szKeyword;
  152. while (!(nComp = *pchKeyword - *pchCandidate) // Be sure to match
  153. && *pchKeyword) // terminating 0's
  154. {
  155. pchKeyword++;
  156. pchCandidate++;
  157. }
  158. // Matched?
  159. if ( 0 == nComp )
  160. return hashTblPtr->token;
  161. }
  162. if ( hashTblPtr->passBit==1 ) // passBit=>another entry to test
  163. {
  164. // step = 1+(hashKey%(HASHSIZE-1));// Calc 'step'
  165. step = 1 + MOD257_1(hashKey);
  166. // Get second entry to check.
  167. index += step;
  168. index = MOD257(index);
  169. hashTblPtr = hashtbl[index];
  170. while (hashTblPtr != NULL ) // While something there.
  171. {
  172. // Compare 2 C strings.
  173. pchCandidate = (BYTE *)hashTblPtr->token->szKeyword;
  174. if ( firstChar == *pchCandidate )
  175. {
  176. pchKeyword = (BYTE *)szKeyword;
  177. while (!(nComp = *pchKeyword - *pchCandidate)
  178. && *pchKeyword)
  179. {
  180. pchKeyword++;
  181. pchCandidate++;
  182. }
  183. // Matched?
  184. if ( 0 == nComp )
  185. return hashTblPtr->token;
  186. }
  187. if ( !hashTblPtr->passBit )// Done searching?
  188. break;
  189. // Get next entry.
  190. index += step;
  191. index = MOD257(index);
  192. hashTblPtr = hashtbl[index];
  193. }
  194. }
  195. }
  196. return NULL;
  197. }
  198. /*
  199. * HashKeyword_Init()
  200. *
  201. * @func
  202. * Load up and init the hash table with RTF control words.
  203. * @devnote
  204. * _rtfHashInited will be FALSE if anything here fails.
  205. */
  206. VOID HashKeyword_Init( )
  207. {
  208. TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "HashKeyword_Init");
  209. extern SHORT cKeywords; // How many RTF keywords we currently recognize.
  210. INT i;
  211. AssertSz( _rtfHashInited == FALSE, "Only need to init this once.");
  212. // Create enough storage for cKeywords
  213. storage = (HashEntry *) PvAlloc( sizeof(HashEntry) * cKeywords, fZeroFill );
  214. // Load in all of the RTF control words.
  215. if ( storage )
  216. {
  217. _rtfHashInited = TRUE;
  218. for (i = 0; i < cKeywords; i++ )
  219. {
  220. HashKeyword_Insert(&rgKeyword[i]);
  221. }
  222. #ifdef DEBUG // Make sure we can fetch all these keywords.
  223. for (i = 0; i < cKeywords; i++ )
  224. {
  225. AssertSz ( &rgKeyword[i] == HashKeyword_Fetch ( rgKeyword[i].szKeyword ),
  226. "Keyword Hash is not working.");
  227. }
  228. #endif
  229. }
  230. }
  231. #endif // RTF_HASHCACHE