7 htret_t
htable_init(htable_t
*htable
, size_t size
, size_t factor
,
14 /* Allocate memory for `size' tailq headers */
15 if ((htable
->ht_table
= malloc(size
* sizeof *htable
->ht_table
)) == NULL
)
18 /* Initialize tailqs */
19 for (i
= 0; i
< size
; i
++)
20 TAILQ_INIT(&htable
->ht_table
[i
]);
22 htable
->ht_size
= size
; /* size must be a power of 2 */
24 htable
->ht_factor
= factor
;
25 htable
->ht_limit
= factor
* size
;
30 /* Setup callback functions */
31 htable
->ht_hashf
= myhashf
;
32 htable
->ht_cmpf
= mycmpf
;
33 htable
->ht_printf
= myprintf
;
38 void htable_free(htable_t
*htable
)
44 for (i
= 0; i
< htable
->ht_size
; i
++) {
45 phead
= &htable
->ht_table
[i
];
46 while ((pnode
= TAILQ_FIRST(phead
)) != NULL
) {
47 TAILQ_REMOVE(phead
, pnode
, hn_next
);
52 free(htable
->ht_table
);
55 htret_t
htable_free_obj(htable_t
*htable
, void *key
, htfree_t htfree
)
62 hash
= htable
->ht_hashf(key
);
65 * Search across chain if there is an entry with the
66 * key we are looking for. If there is, free its contents.
68 phead
= &htable
->ht_table
[hash
& (htable
->ht_size
- 1)];
69 TAILQ_FOREACH(pnode
, phead
, hn_next
) {
70 if (htable
->ht_cmpf(pnode
->hn_key
, key
) == 0) {
71 TAILQ_REMOVE(phead
, pnode
, hn_next
);
72 if (htfree
& HT_FREEKEY
)
74 if (htfree
& HT_FREEDATA
)
85 void htable_free_all_obj(htable_t
*htable
, htfree_t htfree
)
91 for (i
= 0; i
< htable
->ht_size
; i
++) {
92 phead
= &htable
->ht_table
[i
];
93 TAILQ_FOREACH(pnode
, phead
, hn_next
) {
94 if (htfree
& HT_FREEKEY
)
96 if (htfree
& HT_FREEDATA
)
102 htret_t
htable_grow(htable_t
*htable
)
104 hhead_t
*pcurhead
, *pnewhead
, *poldhead
;
106 size_t i
, newhash
, newsize
;
109 * Allocate memory for new hash table
110 * The new hash table is 2 times bigger than the old one
112 newsize
= htable
->ht_size
<< 1;
113 if ((pnewhead
= malloc(newsize
* sizeof *pnewhead
)) == NULL
)
116 /* Initialize tailqs */
117 for (i
= 0; i
< newsize
; i
++)
118 TAILQ_INIT(&pnewhead
[i
]);
120 poldhead
= htable
->ht_table
;
123 * Remove the entries from the old hash table,
124 * rehash them in respect to the new hash table,
125 * and add them to the new one
127 for (i
= 0; i
< htable
->ht_size
; i
++) {
128 pcurhead
= &poldhead
[i
];
129 while ((pnode
= TAILQ_FIRST(pcurhead
)) != NULL
) {
130 newhash
= htable
->ht_hashf(pnode
->hn_key
);
131 TAILQ_REMOVE(pcurhead
, pnode
, hn_next
);
132 TAILQ_INSERT_TAIL(&pnewhead
[newhash
& (newsize
- 1)], pnode
, hn_next
);
137 free(htable
->ht_table
);
139 /* Set new table parameters */
140 htable
->ht_table
= pnewhead
;
141 htable
->ht_size
= newsize
;
142 htable
->ht_limit
= htable
->ht_factor
* newsize
;
147 htret_t
htable_insert(htable_t
*htable
, void *key
, void *data
)
154 hash
= htable
->ht_hashf(key
);
156 /* Search across chain if there is already an entry with the same key. */
157 phead
= &htable
->ht_table
[hash
& (htable
->ht_size
- 1)];
158 TAILQ_FOREACH(pnode
, phead
, hn_next
)
159 if (htable
->ht_cmpf(pnode
->hn_key
, key
) == 0)
162 /* Allocate memory for new entry */
163 if ((pnode
= malloc(sizeof *pnode
)) == NULL
)
166 pnode
->hn_data
= data
;
168 TAILQ_INSERT_TAIL(phead
, pnode
, hn_next
);
170 /* If used items exceed limit, grow the table */
171 if (++htable
->ht_used
> htable
->ht_limit
) {
181 htret_t
htable_remove(htable_t
*htable
, const void *key
)
188 hash
= htable
->ht_hashf(key
);
191 * Search across chain if there is an entry with the
192 * key we are looking. If there is, delete it.
194 phead
= &htable
->ht_table
[hash
& (htable
->ht_size
- 1)];
195 TAILQ_FOREACH(pnode
, phead
, hn_next
) {
196 if (htable
->ht_cmpf(pnode
->hn_key
, key
) == 0) {
197 TAILQ_REMOVE(phead
, pnode
, hn_next
);
207 void *htable_search(const htable_t
*htable
, const void *key
)
209 const hhead_t
*phead
;
210 const hnode_t
*pnode
;
214 hash
= htable
->ht_hashf(key
);
216 phead
= &htable
->ht_table
[hash
& (htable
->ht_size
- 1)];
217 TAILQ_FOREACH(pnode
, phead
, hn_next
)
218 if (htable
->ht_cmpf(pnode
->hn_key
, key
) == 0)
219 return pnode
->hn_data
;
224 void htable_print(const htable_t
*htable
)
226 const hhead_t
*phead
;
227 const hnode_t
*pnode
;
230 for (i
= 0; i
< htable
->ht_size
; i
++) {
231 phead
= &htable
->ht_table
[i
];
232 TAILQ_FOREACH(pnode
, phead
, hn_next
)
233 htable
->ht_printf(pnode
->hn_key
, pnode
->hn_data
);
234 if (TAILQ_FIRST(&htable
->ht_table
[i
]) != NULL
)
239 size_t htable_get_size(const htable_t
*htable
)
241 return htable
->ht_size
;
244 size_t htable_get_used(const htable_t
*htable
)
246 return htable
->ht_used
;
249 void htable_traverse(const htable_t
*htable
, void (*pfunc
)(void *data
))
251 const hhead_t
*phead
;
252 const hnode_t
*pnode
;
255 for (i
= 0; i
< htable
->ht_size
; i
++) {
256 phead
= &htable
->ht_table
[i
];
257 TAILQ_FOREACH(pnode
, phead
, hn_next
)
258 pfunc(pnode
->hn_data
);
262 const hnode_t
*htable_get_next_elm(const htable_t
*htable
, size_t *pos
, const hnode_t
*pnode
)
264 const hhead_t
*phead
;
267 /* Is pos out of bound ? If yes, return immediately */
268 if (*pos
> (htable
->ht_size
- 1))
271 /* Find first usable element, if we were not supplied with one */
272 if (pos
== 0 || pnode
== NULL
) {
273 for (i
= *pos
; i
< htable
->ht_size
; i
++) {
275 phead
= &htable
->ht_table
[i
];
276 if (TAILQ_FIRST(phead
) != NULL
)
277 return TAILQ_FIRST(phead
);
279 /* We have traversed all elements. Nothing left. */
283 /* Are we on a chain ? */
284 if (TAILQ_NEXT(pnode
, hn_next
) != NULL
) {
286 * Don't increase pos since we are stack in an horizontal chain,
287 * being still at the same 'height' which is what pos represents anyway
289 return TAILQ_NEXT(pnode
, hn_next
);
292 for (i
= *pos
; i
< htable
->ht_size
; i
++) {
294 phead
= &htable
->ht_table
[i
];
295 if (TAILQ_FIRST(phead
) != NULL
)
296 return TAILQ_FIRST(phead
);
298 /* We have traversed all elements. Nothing left. */
304 size_t htable_stat_get_grows(const htable_t
*htable
)
306 return htable
->ht_grows
;
309 size_t htable_stat_get_chain_len(const htable_t
*htable
, size_t pos
)
311 const hhead_t
*phead
;
312 const hnode_t
*pnode
;
315 if (pos
>= htable
->ht_size
)
316 return 0; /* FIXME: Better error handling */
319 phead
= &htable
->ht_table
[pos
];
320 TAILQ_FOREACH(pnode
, phead
, hn_next
)