2 This file is part of PulseAudio.
4 Copyright 2004-2008 Lennart Poettering
6 PulseAudio is free software; you can redistribute it and/or modify
7 it under the terms of the GNU Lesser General Public License as published
8 by the Free Software Foundation; either version 2.1 of the License,
9 or (at your option) any later version.
11 PulseAudio is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with PulseAudio; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
28 #include <pulse/xmalloc.h>
29 #include <pulsecore/idxset.h>
30 #include <pulsecore/flist.h>
31 #include <pulsecore/macro.h>
37 struct hashmap_entry {
41 struct hashmap_entry *bucket_next, *bucket_previous;
42 struct hashmap_entry *iterate_next, *iterate_previous;
46 pa_hash_func_t hash_func;
47 pa_compare_func_t compare_func;
49 struct hashmap_entry *iterate_list_head, *iterate_list_tail;
53 #define BY_HASH(h) ((struct hashmap_entry**) ((uint8_t*) (h) + PA_ALIGN(sizeof(pa_hashmap))))
55 PA_STATIC_FLIST_DECLARE(entries, 0, pa_xfree);
57 pa_hashmap *pa_hashmap_new(pa_hash_func_t hash_func, pa_compare_func_t compare_func) {
60 h = pa_xmalloc0(PA_ALIGN(sizeof(pa_hashmap)) + NBUCKETS*sizeof(struct hashmap_entry*));
62 h->hash_func = hash_func ? hash_func : pa_idxset_trivial_hash_func;
63 h->compare_func = compare_func ? compare_func : pa_idxset_trivial_compare_func;
66 h->iterate_list_head = h->iterate_list_tail = NULL;
71 static void remove_entry(pa_hashmap *h, struct hashmap_entry *e) {
75 /* Remove from iteration list */
77 e->iterate_next->iterate_previous = e->iterate_previous;
79 h->iterate_list_tail = e->iterate_previous;
81 if (e->iterate_previous)
82 e->iterate_previous->iterate_next = e->iterate_next;
84 h->iterate_list_head = e->iterate_next;
86 /* Remove from hash table bucket list */
88 e->bucket_next->bucket_previous = e->bucket_previous;
90 if (e->bucket_previous)
91 e->bucket_previous->bucket_next = e->bucket_next;
93 unsigned hash = h->hash_func(e->key) % NBUCKETS;
94 BY_HASH(h)[hash] = e->bucket_next;
97 if (pa_flist_push(PA_STATIC_FLIST_GET(entries), e) < 0)
100 pa_assert(h->n_entries >= 1);
104 void pa_hashmap_free(pa_hashmap *h, pa_free_cb_t free_cb) {
107 pa_hashmap_remove_all(h, free_cb);
111 static struct hashmap_entry *hash_scan(pa_hashmap *h, unsigned hash, const void *key) {
112 struct hashmap_entry *e;
114 pa_assert(hash < NBUCKETS);
116 for (e = BY_HASH(h)[hash]; e; e = e->bucket_next)
117 if (h->compare_func(e->key, key) == 0)
123 int pa_hashmap_put(pa_hashmap *h, const void *key, void *value) {
124 struct hashmap_entry *e;
129 hash = h->hash_func(key) % NBUCKETS;
131 if (hash_scan(h, hash, key))
134 if (!(e = pa_flist_pop(PA_STATIC_FLIST_GET(entries))))
135 e = pa_xnew(struct hashmap_entry, 1);
140 /* Insert into hash table */
141 e->bucket_next = BY_HASH(h)[hash];
142 e->bucket_previous = NULL;
143 if (BY_HASH(h)[hash])
144 BY_HASH(h)[hash]->bucket_previous = e;
145 BY_HASH(h)[hash] = e;
147 /* Insert into iteration list */
148 e->iterate_previous = h->iterate_list_tail;
149 e->iterate_next = NULL;
150 if (h->iterate_list_tail) {
151 pa_assert(h->iterate_list_head);
152 h->iterate_list_tail->iterate_next = e;
154 pa_assert(!h->iterate_list_head);
155 h->iterate_list_head = e;
157 h->iterate_list_tail = e;
160 pa_assert(h->n_entries >= 1);
165 void* pa_hashmap_get(pa_hashmap *h, const void *key) {
167 struct hashmap_entry *e;
171 hash = h->hash_func(key) % NBUCKETS;
173 if (!(e = hash_scan(h, hash, key)))
179 void* pa_hashmap_remove(pa_hashmap *h, const void *key) {
180 struct hashmap_entry *e;
186 hash = h->hash_func(key) % NBUCKETS;
188 if (!(e = hash_scan(h, hash, key)))
197 void pa_hashmap_remove_all(pa_hashmap *h, pa_free_cb_t free_cb) {
200 while (h->iterate_list_head) {
202 data = h->iterate_list_head->value;
203 remove_entry(h, h->iterate_list_head);
210 void *pa_hashmap_iterate(pa_hashmap *h, void **state, const void **key) {
211 struct hashmap_entry *e;
216 if (*state == (void*) -1)
219 if (!*state && !h->iterate_list_head)
222 e = *state ? *state : h->iterate_list_head;
225 *state = e->iterate_next;
235 *state = (void *) -1;
243 void *pa_hashmap_iterate_backwards(pa_hashmap *h, void **state, const void **key) {
244 struct hashmap_entry *e;
249 if (*state == (void*) -1)
252 if (!*state && !h->iterate_list_tail)
255 e = *state ? *state : h->iterate_list_tail;
257 if (e->iterate_previous)
258 *state = e->iterate_previous;
268 *state = (void *) -1;
276 void* pa_hashmap_first(pa_hashmap *h) {
279 if (!h->iterate_list_head)
282 return h->iterate_list_head->value;
285 void* pa_hashmap_last(pa_hashmap *h) {
288 if (!h->iterate_list_tail)
291 return h->iterate_list_tail->value;
294 void* pa_hashmap_steal_first(pa_hashmap *h) {
299 if (!h->iterate_list_head)
302 data = h->iterate_list_head->value;
303 remove_entry(h, h->iterate_list_head);
308 unsigned pa_hashmap_size(pa_hashmap *h) {
314 bool pa_hashmap_isempty(pa_hashmap *h) {
317 return h->n_entries == 0;