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
;
27 /* Setup callback functions */
28 htable
->ht_hashf
= myhashf
;
29 htable
->ht_cmpf
= mycmpf
;
30 htable
->ht_printf
= myprintf
;
35 void htable_free(htable_t
*htable
)
41 for (i
= 0; i
< htable
->ht_size
; i
++) {
42 phead
= &htable
->ht_table
[i
];
43 while ((pnode
= TAILQ_FIRST(phead
)) != NULL
) {
44 TAILQ_REMOVE(phead
, pnode
, hn_next
);
49 free(htable
->ht_table
);
52 htret_t
htable_free_obj(htable_t
*htable
, void *key
, htfree_t htfree
)
59 hash
= htable
->ht_hashf(key
);
62 * Search across chain if there is an entry with the
63 * key we are looking for. If there is, free its contents.
65 phead
= &htable
->ht_table
[hash
& (htable
->ht_size
- 1)];
66 TAILQ_FOREACH(pnode
, phead
, hn_next
) {
67 if (htable
->ht_cmpf(pnode
->hn_key
, key
) == 0) {
68 TAILQ_REMOVE(phead
, pnode
, hn_next
);
69 if (htfree
& HT_FREEKEY
)
71 if (htfree
& HT_FREEDATA
)
82 void htable_free_all_obj(htable_t
*htable
, htfree_t htfree
)
88 for (i
= 0; i
< htable
->ht_size
; i
++) {
89 phead
= &htable
->ht_table
[i
];
90 TAILQ_FOREACH(pnode
, phead
, hn_next
) {
91 if (htfree
& HT_FREEKEY
)
93 if (htfree
& HT_FREEDATA
)
99 htret_t
htable_grow(htable_t
*htable
)
101 hhead_t
*pcurhead
, *pnewhead
, *poldhead
;
103 size_t i
, newhash
, newsize
;
106 * Allocate memory for new hash table
107 * The new hash table is 2 times bigger than the old one
109 newsize
= htable
->ht_size
<< 1;
110 if ((pnewhead
= malloc(newsize
* sizeof *pnewhead
)) == NULL
)
113 /* Initialize tailqs */
114 for (i
= 0; i
< newsize
; i
++)
115 TAILQ_INIT(&pnewhead
[i
]);
117 poldhead
= htable
->ht_table
;
120 * Remove the entries from the old hash table,
121 * rehash them in respect to the new hash table,
122 * and add them to the new one
124 for (i
= 0; i
< htable
->ht_size
; i
++) {
125 pcurhead
= &poldhead
[i
];
126 while ((pnode
= TAILQ_FIRST(pcurhead
)) != NULL
) {
127 newhash
= htable
->ht_hashf(pnode
->hn_key
);
128 TAILQ_REMOVE(pcurhead
, pnode
, hn_next
);
129 TAILQ_INSERT_TAIL(&pnewhead
[newhash
& (newsize
- 1)], pnode
, hn_next
);
134 free(htable
->ht_table
);
136 /* Set new table parameters */
137 htable
->ht_table
= pnewhead
;
138 htable
->ht_size
= newsize
;
139 htable
->ht_limit
= htable
->ht_factor
* newsize
;
144 htret_t
htable_insert(htable_t
*htable
, void *key
, void *data
)
151 hash
= htable
->ht_hashf(key
);
153 /* Search across chain if there is already an entry with the same key. */
154 phead
= &htable
->ht_table
[hash
& (htable
->ht_size
- 1)];
155 TAILQ_FOREACH(pnode
, phead
, hn_next
)
156 if (htable
->ht_cmpf(pnode
->hn_key
, key
) == 0)
159 /* Allocate memory for new entry */
160 if ((pnode
= malloc(sizeof *pnode
)) == NULL
)
163 pnode
->hn_data
= data
;
165 TAILQ_INSERT_TAIL(phead
, pnode
, hn_next
);
167 /* If used items exceed limit, grow the table */
168 if (++htable
->ht_used
> htable
->ht_limit
) {
178 htret_t
htable_remove(htable_t
*htable
, const void *key
)
185 hash
= htable
->ht_hashf(key
);
188 * Search across chain if there is an entry with the
189 * key we are looking. If there is, delete it.
191 phead
= &htable
->ht_table
[hash
& (htable
->ht_size
- 1)];
192 TAILQ_FOREACH(pnode
, phead
, hn_next
) {
193 if (htable
->ht_cmpf(pnode
->hn_key
, key
) == 0) {
194 TAILQ_REMOVE(phead
, pnode
, hn_next
);
204 void *htable_search(const htable_t
*htable
, const void *key
)
206 const hhead_t
*phead
;
207 const hnode_t
*pnode
;
211 hash
= htable
->ht_hashf(key
);
213 phead
= &htable
->ht_table
[hash
& (htable
->ht_size
- 1)];
214 TAILQ_FOREACH(pnode
, phead
, hn_next
)
215 if (htable
->ht_cmpf(pnode
->hn_key
, key
) == 0)
216 return pnode
->hn_data
;
221 void htable_print(const htable_t
*htable
)
223 const hhead_t
*phead
;
224 const hnode_t
*pnode
;
227 for (i
= 0; i
< htable
->ht_size
; i
++) {
228 phead
= &htable
->ht_table
[i
];
229 TAILQ_FOREACH(pnode
, phead
, hn_next
)
230 htable
->ht_printf(pnode
->hn_key
, pnode
->hn_data
);
231 if (TAILQ_FIRST(&htable
->ht_table
[i
]) != NULL
)
236 size_t htable_get_size(const htable_t
*htable
)
238 return htable
->ht_size
;
241 size_t htable_get_used(const htable_t
*htable
)
243 return htable
->ht_used
;
246 void htable_traverse(const htable_t
*htable
, void (*pfunc
)(void *data
))
248 const hhead_t
*phead
;
249 const hnode_t
*pnode
;
252 for (i
= 0; i
< htable
->ht_size
; i
++) {
253 phead
= &htable
->ht_table
[i
];
254 TAILQ_FOREACH(pnode
, phead
, hn_next
)
255 pfunc(pnode
->hn_data
);
259 const hnode_t
*htable_get_next_elm(const htable_t
*htable
, size_t *pos
, const hnode_t
*pnode
)
261 const hhead_t
*phead
;
264 /* Is pos out of bound ? If yes, return immediately */
265 if (*pos
> (htable
->ht_size
- 1))
268 /* Find first usable element, if we were not supplied with one */
269 if (pos
== 0 || pnode
== NULL
) {
270 for (i
= *pos
; i
< htable
->ht_size
; i
++) {
272 phead
= &htable
->ht_table
[i
];
273 if (TAILQ_FIRST(phead
) != NULL
)
274 return TAILQ_FIRST(phead
);
276 /* We have traversed all elements. Nothing left. */
280 /* Are we on a chain ? */
281 if (TAILQ_NEXT(pnode
, hn_next
) != NULL
) {
282 /* Don't increase pos since we are stack in an horizontal chain,
283 being still at the same 'height' which is what pos represents anyway */
284 return TAILQ_NEXT(pnode
, hn_next
);
287 for (i
= *pos
; i
< htable
->ht_size
; i
++) {
289 phead
= &htable
->ht_table
[i
];
290 if (TAILQ_FIRST(phead
) != NULL
)
291 return TAILQ_FIRST(phead
);
293 /* We have traversed all elements. Nothing left. */
299 size_t htable_get_grows(const htable_t
*htable
)
301 return htable
->ht_grows
;