2 * Copyright (c) 1998-2002, Darren Hiebert
4 * This source code is released for free distribution under the terms of the
5 * GNU General Public License version 2 or (at your option) any later version.
7 * Manages a keyword hash.
13 #include "general.h" /* must always come first */
26 typedef struct sHashEntry
{
27 struct sHashEntry
*next
;
36 static const unsigned int TableSize
= 2039; /* prime */
37 static hashEntry
**HashTable
= NULL
;
40 * FUNCTION DEFINITIONS
43 static hashEntry
**getHashTable (void)
45 static bool allocated
= false;
51 HashTable
= xMalloc (TableSize
, hashEntry
*);
53 for (i
= 0 ; i
< TableSize
; ++i
)
61 static hashEntry
*getHashTableEntry (unsigned long hashedValue
)
63 hashEntry
**const table
= getHashTable ();
66 Assert (hashedValue
< TableSize
);
67 entry
= table
[hashedValue
];
72 static unsigned int hashValue (const char *const string
, langType language
)
75 unsigned int h
= 5381;
77 Assert (string
!= NULL
);
79 /* "djb" hash as used in g_str_hash() in glib */
80 for (p
= (const signed char *)string
; *p
!= '\0'; p
++)
81 h
= (h
<< 5) + h
+ tolower (*p
);
83 /* consider language as an extra "character" and add it to the hash */
84 h
= (h
<< 5) + h
+ language
;
89 static hashEntry
*newEntry (
90 const char *const string
, langType language
, int value
)
92 hashEntry
*const entry
= xMalloc (1, hashEntry
);
95 entry
->string
= string
;
96 entry
->language
= language
;
102 /* Note that it is assumed that a "value" of zero means an undefined keyword
103 * and clients of this function should observe this. Also, all keywords added
104 * should be added in lower case. If we encounter a case-sensitive language
105 * whose keywords are in upper case, we will need to redesign this.
107 extern void addKeyword (const char *const string
, langType language
, int value
)
109 const unsigned int index
= hashValue (string
, language
) % TableSize
;
110 hashEntry
*entry
= getHashTableEntry (index
);
114 hashEntry
**const table
= getHashTable ();
115 table
[index
] = newEntry (string
, language
, value
);
119 hashEntry
*prev
= NULL
;
121 while (entry
!= NULL
)
123 if (language
== entry
->language
&&
124 strcmp (string
, entry
->string
) == 0)
126 Assert (("Already in table" == NULL
));
133 Assert (prev
!= NULL
);
134 prev
->next
= newEntry (string
, language
, value
);
139 static int lookupKeywordFull (const char *const string
, bool caseSensitive
, langType language
)
141 const unsigned int index
= hashValue (string
, language
) % TableSize
;
142 hashEntry
*entry
= getHashTableEntry (index
);
143 int result
= KEYWORD_NONE
;
145 while (entry
!= NULL
)
147 if (language
== entry
->language
&&
148 ((caseSensitive
&& strcmp (string
, entry
->string
) == 0) ||
149 (!caseSensitive
&& strcasecmp (string
, entry
->string
) == 0)))
151 result
= entry
->value
;
159 extern int lookupKeyword (const char *const string
, langType language
)
161 return lookupKeywordFull (string
, true, language
);
164 extern int lookupCaseKeyword (const char *const string
, langType language
)
166 return lookupKeywordFull (string
, false, language
);
169 extern void freeKeywordTable (void)
171 if (HashTable
!= NULL
)
175 for (i
= 0 ; i
< TableSize
; ++i
)
177 hashEntry
*entry
= HashTable
[i
];
179 while (entry
!= NULL
)
181 hashEntry
*next
= entry
->next
;
192 static void printEntry (const hashEntry
*const entry
)
194 printf (" %-15s %-7s\n", entry
->string
, getLanguageName (entry
->language
));
197 static unsigned int printBucket (const unsigned int i
)
199 hashEntry
**const table
= getHashTable ();
200 hashEntry
*entry
= table
[i
];
201 unsigned int measure
= 1;
207 else while (entry
!= NULL
)
218 measure
= 2 * measure
;
223 extern void printKeywordTable (void)
225 unsigned long emptyBucketCount
= 0;
226 unsigned long measure
= 0;
229 for (i
= 0 ; i
< TableSize
; ++i
)
231 const unsigned int pass
= printBucket (i
);
238 printf ("spread measure = %ld\n", measure
);
239 printf ("%ld empty buckets\n", emptyBucketCount
);