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
)
174 htret_t
htable_remove(htable_t
*htable
, const void *key
)
181 hash
= htable
->ht_hashf(key
);
184 * Search across chain if there is an entry with the
185 * key we are looking. If there is, delete it.
187 phead
= &htable
->ht_table
[hash
& (htable
->ht_size
- 1)];
188 TAILQ_FOREACH(pnode
, phead
, hn_next
) {
189 if (htable
->ht_cmpf(pnode
->hn_key
, key
) == 0) {
190 TAILQ_REMOVE(phead
, pnode
, hn_next
);
200 void *htable_search(const htable_t
*htable
, const void *key
)
202 const hhead_t
*phead
;
203 const hnode_t
*pnode
;
207 hash
= htable
->ht_hashf(key
);
209 phead
= &htable
->ht_table
[hash
& (htable
->ht_size
- 1)];
210 TAILQ_FOREACH(pnode
, phead
, hn_next
)
211 if (htable
->ht_cmpf(pnode
->hn_key
, key
) == 0)
212 return pnode
->hn_data
;
217 void htable_print(const htable_t
*htable
)
219 const hhead_t
*phead
;
220 const hnode_t
*pnode
;
223 for (i
= 0; i
< htable
->ht_size
; i
++) {
224 phead
= &htable
->ht_table
[i
];
225 TAILQ_FOREACH(pnode
, phead
, hn_next
)
226 htable
->ht_printf(pnode
->hn_key
, pnode
->hn_data
);
227 if (TAILQ_FIRST(&htable
->ht_table
[i
]) != NULL
)
232 size_t htable_get_size(const htable_t
*htable
)
234 return htable
->ht_size
;
237 size_t htable_get_used(const htable_t
*htable
)
239 return htable
->ht_used
;
242 void htable_traverse(const htable_t
*htable
, void (*pfunc
)(void *data
))
244 const hhead_t
*phead
;
245 const hnode_t
*pnode
;
248 for (i
= 0; i
< htable
->ht_size
; i
++) {
249 phead
= &htable
->ht_table
[i
];
250 TAILQ_FOREACH(pnode
, phead
, hn_next
)
251 pfunc(pnode
->hn_data
);
255 const hnode_t
*htable_get_next_elm(const htable_t
*htable
, size_t *pos
, const hnode_t
*pnode
)
257 const hhead_t
*phead
;
260 /* Is pos out of bound ? If yes, return immediately */
261 if (*pos
> (htable
->ht_size
- 1))
264 /* Find first usable element, if we were not supplied with one */
265 if (pos
== 0 || pnode
== NULL
) {
266 for (i
= *pos
; i
< htable
->ht_size
; i
++) {
268 phead
= &htable
->ht_table
[i
];
269 if (TAILQ_FIRST(phead
) != NULL
)
270 return TAILQ_FIRST(phead
);
272 /* We have traversed all elements. Nothing left. */
276 /* Are we on a chain ? */
277 if (TAILQ_NEXT(pnode
, hn_next
) != NULL
) {
278 /* Don't increase pos since we are stack in an horizontal chain,
279 being still at the same 'height' which is what pos represents anyway */
280 return TAILQ_NEXT(pnode
, hn_next
);
283 for (i
= *pos
; i
< htable
->ht_size
; i
++) {
285 phead
= &htable
->ht_table
[i
];
286 if (TAILQ_FIRST(phead
) != NULL
)
287 return TAILQ_FIRST(phead
);
289 /* We have traversed all elements. Nothing left. */