4 This file is part of PulseAudio.
6 Copyright 2004-2006 Lennart Poettering
7 Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
9 PulseAudio is free software; you can redistribute it and/or modify
10 it under the terms of the GNU Lesser General Public License as
11 published by the Free Software Foundation; either version 2.1 of the
12 License, or (at your option) any later version.
14 PulseAudio is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 Lesser General Public License for more details.
19 You should have received a copy of the GNU Lesser General Public
20 License along with PulseAudio; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
34 #include <pulse/xmalloc.h>
35 #include <pulsecore/macro.h>
39 typedef struct idxset_entry {
44 struct idxset_entry *hash_prev, *hash_next;
45 struct idxset_entry* iterate_prev, *iterate_next;
49 pa_hash_func_t hash_func;
50 pa_compare_func_t compare_func;
52 unsigned hash_table_size, n_entries;
53 idxset_entry **hash_table, **array, *iterate_list_head, *iterate_list_tail;
54 uint32_t index, start_index, array_size;
57 unsigned pa_idxset_string_hash_func(const void *p) {
62 hash = 31 * hash + *c;
67 int pa_idxset_string_compare_func(const void *a, const void *b) {
71 unsigned pa_idxset_trivial_hash_func(const void *p) {
72 return PA_PTR_TO_UINT(p);
75 int pa_idxset_trivial_compare_func(const void *a, const void *b) {
79 pa_idxset* pa_idxset_new(pa_hash_func_t hash_func, pa_compare_func_t compare_func) {
82 s = pa_xnew(pa_idxset, 1);
83 s->hash_func = hash_func ? hash_func : pa_idxset_trivial_hash_func;
84 s->compare_func = compare_func ? compare_func : pa_idxset_trivial_compare_func;
85 s->hash_table_size = 127;
86 s->hash_table = pa_xnew0(idxset_entry*, s->hash_table_size);
93 s->iterate_list_head = s->iterate_list_tail = NULL;
98 void pa_idxset_free(pa_idxset *s, void (*free_func) (void *p, void *userdata), void *userdata) {
101 while (s->iterate_list_head) {
102 idxset_entry *e = s->iterate_list_head;
103 s->iterate_list_head = s->iterate_list_head->iterate_next;
106 free_func(e->data, userdata);
110 pa_xfree(s->hash_table);
115 static idxset_entry* hash_scan(pa_idxset *s, idxset_entry* e, const void *p) {
118 assert(s->compare_func);
119 for (; e; e = e->hash_next)
120 if (s->compare_func(e->data, p) == 0)
126 static void extend_array(pa_idxset *s, uint32_t idx) {
129 assert(idx >= s->start_index);
131 if (idx < s->start_index + s->array_size)
134 for (i = 0; i < s->array_size; i++)
138 l = idx - s->start_index - i + 100;
139 n = pa_xnew0(idxset_entry*, l);
141 for (j = 0; j < s->array_size-i; j++)
142 n[j] = s->array[i+j];
151 static idxset_entry** array_index(pa_idxset*s, uint32_t idx) {
152 if (idx >= s->start_index + s->array_size)
155 if (idx < s->start_index)
158 return s->array + idx - s->start_index;
161 int pa_idxset_put(pa_idxset*s, void *p, uint32_t *idx) {
163 idxset_entry *e, **a;
168 assert(s->hash_func);
169 h = s->hash_func(p) % s->hash_table_size;
171 assert(s->hash_table);
172 if ((e = hash_scan(s, s->hash_table[h], p))) {
179 e = pa_xmalloc(sizeof(idxset_entry));
181 e->index = s->index++;
184 /* Insert into hash table */
185 e->hash_next = s->hash_table[h];
187 if (s->hash_table[h])
188 s->hash_table[h]->hash_prev = e;
189 s->hash_table[h] = e;
191 /* Insert into array */
192 extend_array(s, e->index);
193 a = array_index(s, e->index);
197 /* Insert into linked list */
198 e->iterate_next = NULL;
199 e->iterate_prev = s->iterate_list_tail;
200 if (s->iterate_list_tail) {
201 assert(s->iterate_list_head);
202 s->iterate_list_tail->iterate_next = e;
204 assert(!s->iterate_list_head);
205 s->iterate_list_head = e;
207 s->iterate_list_tail = e;
210 assert(s->n_entries >= 1);
218 void* pa_idxset_get_by_index(pa_idxset*s, uint32_t idx) {
222 if (!(a = array_index(s, idx)))
231 void* pa_idxset_get_by_data(pa_idxset*s, const void *p, uint32_t *idx) {
236 assert(s->hash_func);
237 h = s->hash_func(p) % s->hash_table_size;
239 assert(s->hash_table);
240 if (!(e = hash_scan(s, s->hash_table[h], p)))
249 static void remove_entry(pa_idxset *s, idxset_entry *e) {
253 /* Remove from array */
254 a = array_index(s, e->index);
255 assert(a && *a && *a == e);
258 /* Remove from linked list */
260 e->iterate_next->iterate_prev = e->iterate_prev;
262 s->iterate_list_tail = e->iterate_prev;
265 e->iterate_prev->iterate_next = e->iterate_next;
267 s->iterate_list_head = e->iterate_next;
269 /* Remove from hash table */
271 e->hash_next->hash_prev = e->hash_prev;
274 e->hash_prev->hash_next = e->hash_next;
276 s->hash_table[e->hash_value] = e->hash_next;
280 assert(s->n_entries >= 1);
284 void* pa_idxset_remove_by_index(pa_idxset*s, uint32_t idx) {
290 if (!(a = array_index(s, idx)))
302 void* pa_idxset_remove_by_data(pa_idxset*s, const void *data, uint32_t *idx) {
307 assert(s->hash_func);
308 h = s->hash_func(data) % s->hash_table_size;
310 assert(s->hash_table);
311 if (!(e = hash_scan(s, s->hash_table[h], data)))
323 void* pa_idxset_rrobin(pa_idxset *s, uint32_t *idx) {
324 idxset_entry **a, *e = NULL;
327 if ((a = array_index(s, *idx)) && *a)
328 e = (*a)->iterate_next;
331 e = s->iterate_list_head;
340 void* pa_idxset_first(pa_idxset *s, uint32_t *idx) {
343 if (!s->iterate_list_head)
347 *idx = s->iterate_list_head->index;
348 return s->iterate_list_head->data;
351 void *pa_idxset_next(pa_idxset *s, uint32_t *idx) {
352 idxset_entry **a, *e = NULL;
356 if ((a = array_index(s, *idx)) && *a)
357 e = (*a)->iterate_next;
363 *idx = PA_IDXSET_INVALID;
368 int pa_idxset_foreach(pa_idxset*s, int (*func)(void *p, uint32_t idx, int *del, void*userdata), void *userdata) {
372 e = s->iterate_list_head;
375 idxset_entry *n = e->iterate_next;
377 r = func(e->data, e->index, &del, userdata);
391 unsigned pa_idxset_size(pa_idxset*s) {
396 int pa_idxset_isempty(pa_idxset *s) {
398 return s->n_entries == 0;