181d319a6217512d8e64c3f5a43a02cb5feb6256
1 /* hash.c - hash tables for opkg
3 Steven M. Ayer, Jamey Hicks
5 Copyright (C) 2002 Compaq Computer Corporation
7 This program is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation; either version 2, or (at
10 your option) any later version.
12 This program is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
22 #include "hash_table.h"
23 #include "opkg_message.h"
24 #include "libbb/libbb.h"
28 djb2_hash(const unsigned char *str
)
30 unsigned long hash
= 5381;
33 hash
= ((hash
<< 5) + hash
) + c
; /* hash * 33 + c */
38 hash_index(hash_table_t
*hash
, const char *key
)
40 return djb2_hash((const unsigned char *)key
) % hash
->n_buckets
;
44 * this is an open table keyed by strings
47 hash_table_init(const char *name
, hash_table_t
*hash
, int len
)
49 if (hash
->entries
!= NULL
) {
50 fprintf(stderr
, "ERROR: %s called on a non empty hash table\n",
55 memset(hash
, 0, sizeof(hash_table_t
));
58 hash
->n_buckets
= len
;
59 hash
->entries
= xcalloc(hash
->n_buckets
, sizeof(hash_entry_t
));
65 hash_print_stats(hash_table_t
*hash
)
67 printf("hash_table: %s, %d bytes\n"
68 "\tn_buckets=%d, n_elements=%d, n_collisions=%d\n"
69 "\tmax_bucket_len=%d, n_used_buckets=%d, ave_bucket_len=%.2f\n"
70 "\tn_hits=%d, n_misses=%d\n",
72 hash
->n_buckets
*(int)sizeof(hash_entry_t
),
78 (hash
->n_used_buckets
?
79 ((float)hash
->n_elements
)/hash
->n_used_buckets
: 0.0f
),
84 void hash_table_deinit(hash_table_t
*hash
)
90 /* free the reminaing entries */
91 for (i
= 0; i
< hash
->n_buckets
; i
++) {
92 hash_entry_t
*hash_entry
= (hash
->entries
+ i
);
93 free (hash_entry
->key
);
94 /* skip the first entry as this is part of the array */
95 hash_entry
= hash_entry
->next
;
98 hash_entry_t
*old
= hash_entry
;
99 hash_entry
= hash_entry
->next
;
105 free (hash
->entries
);
107 hash
->entries
= NULL
;
111 void *hash_table_get(hash_table_t
*hash
, const char *key
)
113 int ndx
= hash_index(hash
, key
);
114 hash_entry_t
*hash_entry
= hash
->entries
+ ndx
;
119 if (strcmp(key
, hash_entry
->key
) == 0) {
120 // opkg_message(NULL, OPKG_DEBUG, "Function: %s. Key found for '%s' \n", __FUNCTION__, key);
122 return hash_entry
->data
;
125 hash_entry
= hash_entry
->next
;
131 int hash_table_insert(hash_table_t
*hash
, const char *key
, void *value
)
134 int ndx
= hash_index(hash
, key
);
135 hash_entry_t
*hash_entry
= hash
->entries
+ ndx
;
136 if (hash_entry
->key
) {
137 if (strcmp(hash_entry
->key
, key
) == 0) {
138 /* alread in table, update the value */
139 hash_entry
->data
= value
;
143 * if this is a collision, we have to go to the end of the ll,
144 * then add a new entry
145 * before we can hook up the value
147 while (hash_entry
->next
) {
148 hash_entry
= hash_entry
->next
;
149 if (strcmp(hash_entry
->key
, key
) == 0) {
150 hash_entry
->data
= value
;
155 hash_entry
->next
= xcalloc(1, sizeof(hash_entry_t
));
156 hash_entry
= hash_entry
->next
;
157 hash_entry
->next
= NULL
;
159 hash
->n_collisions
++;
160 if (++bucket_len
> hash
->max_bucket_len
)
161 hash
->max_bucket_len
= bucket_len
;
164 hash
->n_used_buckets
++;
167 hash_entry
->key
= xstrdup(key
);
168 hash_entry
->data
= value
;
173 int hash_table_remove(hash_table_t
*hash
, const char *key
)
175 int ndx
= hash_index(hash
, key
);
176 hash_entry_t
*hash_entry
= hash
->entries
+ ndx
;
177 hash_entry_t
*next_entry
=NULL
, *last_entry
=NULL
;
182 if (strcmp(key
, hash_entry
->key
) == 0) {
183 free(hash_entry
->key
);
185 last_entry
->next
= hash_entry
->next
;
188 next_entry
= hash_entry
->next
;
190 memmove(hash_entry
, next_entry
, sizeof(hash_entry_t
));
193 memset(hash_entry
, 0 , sizeof(hash_entry_t
));
199 last_entry
= hash_entry
;
200 hash_entry
= hash_entry
->next
;
205 void hash_table_foreach(hash_table_t
*hash
, void (*f
)(const char *key
, void *entry
, void *data
), void *data
)
211 for (i
= 0; i
< hash
->n_buckets
; i
++) {
212 hash_entry_t
*hash_entry
= (hash
->entries
+ i
);
214 if(hash_entry
->key
) {
215 f(hash_entry
->key
, hash_entry
->data
, data
);
217 } while((hash_entry
= hash_entry
->next
));