1 /* This is a public domain general purpose hash table package written by Peter Moore @ UCB. */
3 /* static char sccsid[] = "@(#) st.c 5.1 89/12/14 Crucible"; */
8 #include "OnigurumaUefiPort.h"
17 typedef struct st_table_entry st_table_entry
;
19 struct st_table_entry
{
26 #define ST_DEFAULT_MAX_DENSITY 5
27 #define ST_DEFAULT_INIT_TABLE_SIZE 11
30 * DEFAULT_MAX_DENSITY is the default for the largest we allow the
31 * average number of items per bin before increasing the number of
34 * DEFAULT_INIT_TABLE_SIZE is the default for the number of bins
39 static int numcmp(long, long);
40 static int numhash(long);
41 static struct st_hash_type type_numhash
= {
46 /* extern int strcmp(const char *, const char *); */
47 static int strhash(const char *);
48 static struct st_hash_type type_strhash
= {
53 static void rehash(st_table
*);
55 #define alloc(type) (type*)xmalloc((unsigned)sizeof(type))
56 #define Calloc(n,s) (char*)xcalloc((n),(s))
58 #define EQUAL(table,x,y) ((x)==(y) || (*table->type->compare)((x),(y)) == 0)
60 #define do_hash(key,table) (unsigned int)(*(table)->type->hash)((key))
61 #define do_hash_bin(key,table) (do_hash(key, table)%(table)->num_bins)
64 * MINSIZE is the minimum size of a dictionary.
70 Table of prime numbers 2^n+a, 2<=n<=30.
72 static const long primes
[] = {
111 for (i
=3; i
<31; i
++) {
112 if ((1<<i
) > size
) return 1<<i
;
118 for (i
= 0, newsize
= MINSIZE
;
119 i
< (int )(sizeof(primes
)/sizeof(primes
[0]));
122 if (newsize
> size
) return primes
[i
];
124 /* Ran out of polynomials */
125 return -1; /* should raise exception */
130 static int collision
= 0;
131 static int init_st
= 0;
136 FILE *f
= fopen("/tmp/col", "w");
137 fprintf(f
, "collision: %d\n", collision
);
143 st_init_table_with_size(type
, size
)
144 struct st_hash_type
*type
;
156 size
= new_size(size
); /* round up to prime number */
158 tbl
= alloc(st_table
);
160 tbl
->num_entries
= 0;
161 tbl
->num_bins
= size
;
162 tbl
->bins
= (st_table_entry
**)Calloc(size
, sizeof(st_table_entry
*));
169 struct st_hash_type
*type
;
171 return st_init_table_with_size(type
, 0);
175 st_init_numtable(void)
177 return st_init_table(&type_numhash
);
181 st_init_numtable_with_size(size
)
184 return st_init_table_with_size(&type_numhash
, size
);
188 st_init_strtable(void)
190 return st_init_table(&type_strhash
);
194 st_init_strtable_with_size(size
)
197 return st_init_table_with_size(&type_strhash
, size
);
204 register st_table_entry
*ptr
, *next
;
207 for(i
= 0; i
< table
->num_bins
; i
++) {
208 ptr
= table
->bins
[i
];
219 #define PTR_NOT_EQUAL(table, ptr, hash_val, key) \
220 ((ptr) != 0 && (ptr->hash != (hash_val) || !EQUAL((table), (key), (ptr)->key)))
223 #define COLLISION collision++
228 #define FIND_ENTRY(table, ptr, hash_val, bin_pos) do {\
229 bin_pos = hash_val%(table)->num_bins;\
230 ptr = (table)->bins[bin_pos];\
231 if (PTR_NOT_EQUAL(table, ptr, hash_val, key)) {\
233 while (PTR_NOT_EQUAL(table, ptr->next, hash_val, key)) {\
241 st_lookup(table
, key
, value
)
243 register st_data_t key
;
246 unsigned int hash_val
, bin_pos
;
247 register st_table_entry
*ptr
;
249 hash_val
= do_hash(key
, table
);
250 FIND_ENTRY(table
, ptr
, hash_val
, bin_pos
);
256 if (value
!= 0) *value
= ptr
->record
;
261 #define ADD_DIRECT(table, key, value, hash_val, bin_pos)\
263 st_table_entry *entry;\
264 if (table->num_entries/(table->num_bins) > ST_DEFAULT_MAX_DENSITY) {\
266 bin_pos = hash_val % table->num_bins;\
269 entry = alloc(st_table_entry);\
271 entry->hash = hash_val;\
273 entry->record = value;\
274 entry->next = table->bins[bin_pos];\
275 table->bins[bin_pos] = entry;\
276 table->num_entries++;\
280 st_insert(table
, key
, value
)
281 register st_table
*table
;
282 register st_data_t key
;
285 unsigned int hash_val
, bin_pos
;
286 register st_table_entry
*ptr
;
288 hash_val
= do_hash(key
, table
);
289 FIND_ENTRY(table
, ptr
, hash_val
, bin_pos
);
292 ADD_DIRECT(table
, key
, value
, hash_val
, bin_pos
);
302 st_add_direct(table
, key
, value
)
307 unsigned int hash_val
, bin_pos
;
309 hash_val
= do_hash(key
, table
);
310 bin_pos
= hash_val
% table
->num_bins
;
311 ADD_DIRECT(table
, key
, value
, hash_val
, bin_pos
);
316 register st_table
*table
;
318 register st_table_entry
*ptr
, *next
, **new_bins
;
319 int i
, old_num_bins
= table
->num_bins
, new_num_bins
;
320 unsigned int hash_val
;
322 new_num_bins
= new_size(old_num_bins
+1);
323 new_bins
= (st_table_entry
**)Calloc(new_num_bins
, sizeof(st_table_entry
*));
325 for(i
= 0; i
< old_num_bins
; i
++) {
326 ptr
= table
->bins
[i
];
329 hash_val
= ptr
->hash
% new_num_bins
;
330 ptr
->next
= new_bins
[hash_val
];
331 new_bins
[hash_val
] = ptr
;
336 table
->num_bins
= new_num_bins
;
337 table
->bins
= new_bins
;
345 st_table_entry
*ptr
, *entry
;
346 int i
, num_bins
= old_table
->num_bins
;
348 new_table
= alloc(st_table
);
349 if (new_table
== 0) {
353 *new_table
= *old_table
;
354 new_table
->bins
= (st_table_entry
**)
355 Calloc((unsigned)num_bins
, sizeof(st_table_entry
*));
357 if (new_table
->bins
== 0) {
362 for(i
= 0; i
< num_bins
; i
++) {
363 new_table
->bins
[i
] = 0;
364 ptr
= old_table
->bins
[i
];
366 entry
= alloc(st_table_entry
);
368 free(new_table
->bins
);
373 entry
->next
= new_table
->bins
[i
];
374 new_table
->bins
[i
] = entry
;
382 st_delete(table
, key
, value
)
383 register st_table
*table
;
384 register st_data_t
*key
;
387 unsigned int hash_val
;
389 register st_table_entry
*ptr
;
391 hash_val
= do_hash_bin(*key
, table
);
392 ptr
= table
->bins
[hash_val
];
395 if (value
!= 0) *value
= 0;
399 if (EQUAL(table
, *key
, ptr
->key
)) {
400 table
->bins
[hash_val
] = ptr
->next
;
401 table
->num_entries
--;
402 if (value
!= 0) *value
= ptr
->record
;
408 for(; ptr
->next
!= 0; ptr
= ptr
->next
) {
409 if (EQUAL(table
, ptr
->next
->key
, *key
)) {
411 ptr
->next
= ptr
->next
->next
;
412 table
->num_entries
--;
413 if (value
!= 0) *value
= tmp
->record
;
424 st_delete_safe(table
, key
, value
, never
)
425 register st_table
*table
;
426 register st_data_t
*key
;
430 unsigned int hash_val
;
431 register st_table_entry
*ptr
;
433 hash_val
= do_hash_bin(*key
, table
);
434 ptr
= table
->bins
[hash_val
];
437 if (value
!= 0) *value
= 0;
441 for(; ptr
!= 0; ptr
= ptr
->next
) {
442 if ((ptr
->key
!= never
) && EQUAL(table
, ptr
->key
, *key
)) {
443 table
->num_entries
--;
445 if (value
!= 0) *value
= ptr
->record
;
446 ptr
->key
= ptr
->record
= never
;
455 #if defined(__GNUC__)
456 delete_never(st_data_t key
__attribute__ ((unused
)), st_data_t value
,
459 delete_never(key
, value
, never
)
460 st_data_t key
, value
, never
;
463 if (value
== never
) return ST_DELETE
;
468 st_cleanup_safe(table
, never
)
472 int num_entries
= table
->num_entries
;
474 st_foreach(table
, delete_never
, never
);
475 table
->num_entries
= num_entries
;
479 st_foreach(table
, func
, arg
)
484 st_table_entry
*ptr
, *last
, *tmp
;
485 enum st_retval retval
;
488 for(i
= 0; i
< table
->num_bins
; i
++) {
490 for(ptr
= table
->bins
[i
]; ptr
!= 0;) {
491 retval
= (*func
)(ptr
->key
, ptr
->record
, arg
);
493 case ST_CHECK
: /* check if hash is modified during iteration */
495 if (i
< table
->num_bins
) {
496 for (tmp
= table
->bins
[i
]; tmp
; tmp
=tmp
->next
) {
497 if (tmp
== ptr
) break;
501 /* call func with error notice */
514 table
->bins
[i
] = ptr
->next
;
517 last
->next
= ptr
->next
;
521 table
->num_entries
--;
530 register const char *string
;
535 register unsigned int h
= 0, g
;
537 while ((c
= *string
++) != '\0') {
539 if ( g
= h
& 0xF0000000 )
545 register int val
= 0;
547 while ((c
= *string
++) != '\0') {
555 return val
+ (val
<< 15);
557 register int val
= 0;
559 while ((c
= *string
++) != '\0') {
563 return val
+ (val
>>5);