@@ -12,7 +12,8 @@ See the file COPYING for details.
1212#include <string.h>
1313
1414#define DEFAULT_SIZE 127
15- #define DEFAULT_LOAD 0.75
15+ #define DEFAULT_MAX_LOAD 0.75
16+ #define DEFAULT_MIN_LOAD 0.125
1617#define DEFAULT_FUNC hash_string
1718
1819struct entry {
@@ -155,72 +156,113 @@ int hash_table_size(struct hash_table *h)
155156 return h -> size ;
156157}
157158
158- static int hash_table_double_buckets (struct hash_table * h )
159+ double hash_table_load (struct hash_table * h )
159160{
160- struct hash_table * hn = hash_table_create (2 * h -> bucket_count , h -> hash_func );
161+ return ((double )h -> size ) / h -> bucket_count ;
162+ }
161163
162- if (!hn )
163- return 0 ;
164+ static int insert_to_buckets_aux (struct entry * * buckets , int bucket_count , struct entry * new_entry )
165+ {
166+ unsigned index ;
167+ struct entry * e ;
164168
165- /* Move pairs to new hash */
166- char * key ;
167- void * value ;
168- hash_table_firstkey (h );
169- while (hash_table_nextkey (h , & key , & value ))
170- if (!hash_table_insert (hn , key , value )) {
171- hash_table_delete (hn );
169+ index = new_entry -> hash % bucket_count ;
170+ e = buckets [index ];
171+
172+ while (e ) {
173+ /* check that this key does not already exist in the table */
174+ if (new_entry -> hash == e -> hash && !strcmp (new_entry -> key , e -> key )) {
172175 return 0 ;
173176 }
177+ e = e -> next ;
178+ }
179+
180+ new_entry -> next = buckets [index ];
181+ buckets [index ] = new_entry ;
182+
183+ return 1 ;
184+ }
185+
186+ static int hash_table_double_buckets (struct hash_table * h )
187+ {
188+ int new_count = (2 * (h -> bucket_count + 1 )) - 1 ;
189+ struct entry * * new_buckets = (struct entry * * )calloc (new_count , sizeof (struct entry * ));
190+ if (!new_buckets ) {
191+ return 0 ;
192+ }
174193
175- /* Delete all old pairs */
176194 struct entry * e , * f ;
177- int i ;
178- for (i = 0 ; i < h -> bucket_count ; i ++ ) {
195+ for (int i = 0 ; i < h -> bucket_count ; i ++ ) {
179196 e = h -> buckets [i ];
180197 while (e ) {
181198 f = e -> next ;
182- free ( e -> key ) ;
183- free ( e );
199+ e -> next = NULL ;
200+ insert_to_buckets_aux ( new_buckets , new_count , e );
184201 e = f ;
185202 }
186203 }
187204
188205 /* Make the old point to the new */
189206 free (h -> buckets );
190- h -> buckets = hn -> buckets ;
191- h -> bucket_count = hn -> bucket_count ;
192- h -> size = hn -> size ;
207+ h -> buckets = new_buckets ;
208+ h -> bucket_count = new_count ;
193209
194210 /* structure of hash table changed completely, thus a nextkey would be incorrect. */
195211 h -> cant_iterate_yet = 1 ;
196212
197- /* Delete reference to new, so old is safe */
198- free (hn );
199-
200213 return 1 ;
201214}
202215
203- int hash_table_insert (struct hash_table * h , const char * key , const void * value )
216+ static int hash_table_reduce_buckets (struct hash_table * h )
204217{
205- struct entry * e ;
206- unsigned hash , index ;
218+ int new_count = ((h -> bucket_count + 1 ) / 2 ) - 1 ;
207219
208- if (((float )h -> size / h -> bucket_count ) > DEFAULT_LOAD )
209- hash_table_double_buckets (h );
220+ /* DEFAULT_SIZE is the minimum size */
221+ if (new_count < DEFAULT_SIZE ) {
222+ return 1 ;
223+ }
210224
211- hash = h -> hash_func (key );
212- index = hash % h -> bucket_count ;
213- e = h -> buckets [index ];
225+ /* Table cannot be reduced above DEFAULT_MAX_LOAD */
226+ if (((float )h -> size / new_count ) > DEFAULT_MAX_LOAD ) {
227+ return 1 ;
228+ }
214229
215- while (e ) {
216- if (hash == e -> hash && !strcmp (key , e -> key ))
217- return 0 ;
218- e = e -> next ;
230+ struct entry * * new_buckets = (struct entry * * )calloc (new_count , sizeof (struct entry * ));
231+ if (!new_buckets ) {
232+ return 0 ;
219233 }
220234
221- e = (struct entry * )malloc (sizeof (struct entry ));
222- if (!e )
235+ struct entry * e , * f ;
236+ for (int i = 0 ; i < h -> bucket_count ; i ++ ) {
237+ e = h -> buckets [i ];
238+ while (e ) {
239+ f = e -> next ;
240+ e -> next = NULL ;
241+ insert_to_buckets_aux (new_buckets , new_count , e );
242+ e = f ;
243+ }
244+ }
245+
246+ /* Make the old point to the new */
247+ free (h -> buckets );
248+ h -> buckets = new_buckets ;
249+ h -> bucket_count = new_count ;
250+
251+ /* structure of hash table changed completely, thus a nextkey would be incorrect. */
252+ h -> cant_iterate_yet = 1 ;
253+
254+ return 1 ;
255+ }
256+
257+ int hash_table_insert (struct hash_table * h , const char * key , const void * value )
258+ {
259+ if (((float )h -> size / h -> bucket_count ) > DEFAULT_MAX_LOAD )
260+ hash_table_double_buckets (h );
261+
262+ struct entry * e = (struct entry * )malloc (sizeof (struct entry ));
263+ if (!e ) {
223264 return 0 ;
265+ }
224266
225267 e -> key = strdup (key );
226268 if (!e -> key ) {
@@ -229,16 +271,18 @@ int hash_table_insert(struct hash_table *h, const char *key, const void *value)
229271 }
230272
231273 e -> value = (void * )value ;
232- e -> hash = hash ;
233- e -> next = h -> buckets [index ];
234- h -> buckets [index ] = e ;
235- h -> size ++ ;
274+ e -> hash = h -> hash_func (e -> key );
236275
237- /* inserting cause different behaviours with nextkey (e.g., sometimes the new
238- * key would be included or skipped in the iteration */
239- h -> cant_iterate_yet = 1 ;
276+ int inserted = insert_to_buckets_aux ( h -> buckets , h -> bucket_count , e );
277+ if ( inserted ) {
278+ h -> size ++ ;
240279
241- return 1 ;
280+ /* inserting cause different behaviours with nextkey (e.g., sometimes the new
281+ * key would be included or skipped in the iteration */
282+ h -> cant_iterate_yet = 1 ;
283+ }
284+
285+ return inserted ;
242286}
243287
244288void * hash_table_remove (struct hash_table * h , const char * key )
@@ -264,8 +308,9 @@ void *hash_table_remove(struct hash_table *h, const char *key)
264308 free (e );
265309 h -> size -- ;
266310
267- /* the deletion may cause nextkey to fail */
268- h -> cant_iterate_yet = 1 ;
311+ if (((float )h -> size / h -> bucket_count ) < DEFAULT_MIN_LOAD ) {
312+ hash_table_reduce_buckets (h );
313+ }
269314
270315 return value ;
271316 }
0 commit comments