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
);
183 /* Search across chain if there is an entry with the
184 key we are looking. If there is, remove it. */
185 phead
= &htable
->ht_table
[hash
& (htable
->ht_size
- 1)];
186 TAILQ_FOREACH(pnode
, phead
, hn_next
) {
187 if (htable
->ht_cmpf(pnode
->hn_key
, key
) == 0) {
188 TAILQ_REMOVE(phead
, pnode
, hn_next
);
198 void *htable_search(const htable_t
*htable
, const void *key
)
200 const hhead_t
*phead
;
201 const hnode_t
*pnode
;
205 hash
= htable
->ht_hashf(key
);
207 phead
= &htable
->ht_table
[hash
& (htable
->ht_size
- 1)];
208 TAILQ_FOREACH(pnode
, phead
, hn_next
)
209 if (htable
->ht_cmpf(pnode
->hn_key
, key
) == 0)
210 return pnode
->hn_data
;
215 void htable_print(const htable_t
*htable
)
217 const hhead_t
*phead
;
218 const hnode_t
*pnode
;
221 for (i
= 0; i
< htable
->ht_size
; i
++) {
222 phead
= &htable
->ht_table
[i
];
223 TAILQ_FOREACH(pnode
, phead
, hn_next
)
224 htable
->ht_printf(pnode
->hn_key
, pnode
->hn_data
);
225 if (TAILQ_FIRST(&htable
->ht_table
[i
]) != NULL
)
230 size_t htable_get_size(const htable_t
*htable
)
232 return htable
->ht_size
;
235 size_t htable_get_used(const htable_t
*htable
)
237 return htable
->ht_used
;
240 void htable_traverse(const htable_t
*htable
, void (*pfunc
)(void *data
))
242 const hhead_t
*phead
;
243 const hnode_t
*pnode
;
246 for (i
= 0; i
< htable
->ht_size
; i
++) {
247 phead
= &htable
->ht_table
[i
];
248 TAILQ_FOREACH(pnode
, phead
, hn_next
)
249 pfunc(pnode
->hn_data
);
253 const hnode_t
*htable_get_next_elm(const htable_t
*htable
, size_t *pos
, const hnode_t
*pnode
)
255 const hhead_t
*phead
;
258 /* Is pos out of bound ? If yes, return immediately */
259 if (*pos
> (htable
->ht_size
- 1))
262 /* Find first usable element, if we were not supplied with one */
263 if (pos
== 0 || pnode
== NULL
) {
264 for (i
= *pos
; i
< htable
->ht_size
; i
++) {
266 phead
= &htable
->ht_table
[i
];
267 if (TAILQ_FIRST(phead
) != NULL
)
268 return TAILQ_FIRST(phead
);
272 /* Are we on a chain ? */
273 if (TAILQ_NEXT(pnode
, hn_next
) != NULL
) {
274 /* Don't increase pos since we are stack in an horizontal chain,
275 being still at the same 'height' which is what pos represents anyway */
276 return TAILQ_NEXT(pnode
, hn_next
);
279 for (i
= *pos
; i
< htable
->ht_size
; i
++) {
281 phead
= &htable
->ht_table
[i
];
282 if (TAILQ_FIRST(phead
) != NULL
)
283 return TAILQ_FIRST(phead
);
285 /* We have traversed all elements. Nothing left. */