1
/* $Id: idxset.c 1262 2006-08-18 19:42:14Z lennart $ */
4
This file is part of PulseAudio.
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
8
published by the Free Software Foundation; either version 2.1 of the
9
License, 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
Lesser General Public License for more details.
16
You should have received a copy of the GNU Lesser General Public
17
License along with PulseAudio; if not, write to the Free Software
18
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
31
#include <pulse/xmalloc.h>
35
typedef struct idxset_entry {
40
struct idxset_entry *hash_prev, *hash_next;
41
struct idxset_entry* iterate_prev, *iterate_next;
45
pa_hash_func_t hash_func;
46
pa_compare_func_t compare_func;
48
unsigned hash_table_size, n_entries;
49
idxset_entry **hash_table, **array, *iterate_list_head, *iterate_list_tail;
50
uint32_t index, start_index, array_size;
53
unsigned pa_idxset_string_hash_func(const void *p) {
58
hash = 31 * hash + *c;
63
int pa_idxset_string_compare_func(const void *a, const void *b) {
67
unsigned pa_idxset_trivial_hash_func(const void *p) {
68
return PA_PTR_TO_UINT(p);
71
int pa_idxset_trivial_compare_func(const void *a, const void *b) {
75
pa_idxset* pa_idxset_new(pa_hash_func_t hash_func, pa_compare_func_t compare_func) {
78
s = pa_xnew(pa_idxset, 1);
79
s->hash_func = hash_func ? hash_func : pa_idxset_trivial_hash_func;
80
s->compare_func = compare_func ? compare_func : pa_idxset_trivial_compare_func;
81
s->hash_table_size = 127;
82
s->hash_table = pa_xnew0(idxset_entry*, s->hash_table_size);
89
s->iterate_list_head = s->iterate_list_tail = NULL;
94
void pa_idxset_free(pa_idxset *s, void (*free_func) (void *p, void *userdata), void *userdata) {
97
while (s->iterate_list_head) {
98
idxset_entry *e = s->iterate_list_head;
99
s->iterate_list_head = s->iterate_list_head->iterate_next;
102
free_func(e->data, userdata);
106
pa_xfree(s->hash_table);
111
static idxset_entry* hash_scan(pa_idxset *s, idxset_entry* e, const void *p) {
114
assert(s->compare_func);
115
for (; e; e = e->hash_next)
116
if (s->compare_func(e->data, p) == 0)
122
static void extend_array(pa_idxset *s, uint32_t idx) {
125
assert(idx >= s->start_index);
127
if (idx < s->start_index + s->array_size)
130
for (i = 0; i < s->array_size; i++)
134
l = idx - s->start_index - i + 100;
135
n = pa_xnew0(idxset_entry*, l);
137
for (j = 0; j < s->array_size-i; j++)
138
n[j] = s->array[i+j];
147
static idxset_entry** array_index(pa_idxset*s, uint32_t idx) {
148
if (idx >= s->start_index + s->array_size)
151
if (idx < s->start_index)
154
return s->array + idx - s->start_index;
157
int pa_idxset_put(pa_idxset*s, void *p, uint32_t *idx) {
159
idxset_entry *e, **a;
164
assert(s->hash_func);
165
h = s->hash_func(p) % s->hash_table_size;
167
assert(s->hash_table);
168
if ((e = hash_scan(s, s->hash_table[h], p))) {
175
e = pa_xmalloc(sizeof(idxset_entry));
177
e->index = s->index++;
180
/* Insert into hash table */
181
e->hash_next = s->hash_table[h];
183
if (s->hash_table[h])
184
s->hash_table[h]->hash_prev = e;
185
s->hash_table[h] = e;
187
/* Insert into array */
188
extend_array(s, e->index);
189
a = array_index(s, e->index);
193
/* Insert into linked list */
194
e->iterate_next = NULL;
195
e->iterate_prev = s->iterate_list_tail;
196
if (s->iterate_list_tail) {
197
assert(s->iterate_list_head);
198
s->iterate_list_tail->iterate_next = e;
200
assert(!s->iterate_list_head);
201
s->iterate_list_head = e;
203
s->iterate_list_tail = e;
206
assert(s->n_entries >= 1);
214
void* pa_idxset_get_by_index(pa_idxset*s, uint32_t idx) {
218
if (!(a = array_index(s, idx)))
227
void* pa_idxset_get_by_data(pa_idxset*s, const void *p, uint32_t *idx) {
232
assert(s->hash_func);
233
h = s->hash_func(p) % s->hash_table_size;
235
assert(s->hash_table);
236
if (!(e = hash_scan(s, s->hash_table[h], p)))
245
static void remove_entry(pa_idxset *s, idxset_entry *e) {
249
/* Remove from array */
250
a = array_index(s, e->index);
251
assert(a && *a && *a == e);
254
/* Remove from linked list */
256
e->iterate_next->iterate_prev = e->iterate_prev;
258
s->iterate_list_tail = e->iterate_prev;
261
e->iterate_prev->iterate_next = e->iterate_next;
263
s->iterate_list_head = e->iterate_next;
265
/* Remove from hash table */
267
e->hash_next->hash_prev = e->hash_prev;
270
e->hash_prev->hash_next = e->hash_next;
272
s->hash_table[e->hash_value] = e->hash_next;
276
assert(s->n_entries >= 1);
280
void* pa_idxset_remove_by_index(pa_idxset*s, uint32_t idx) {
286
if (!(a = array_index(s, idx)))
298
void* pa_idxset_remove_by_data(pa_idxset*s, const void *data, uint32_t *idx) {
303
assert(s->hash_func);
304
h = s->hash_func(data) % s->hash_table_size;
306
assert(s->hash_table);
307
if (!(e = hash_scan(s, s->hash_table[h], data)))
319
void* pa_idxset_rrobin(pa_idxset *s, uint32_t *idx) {
320
idxset_entry **a, *e = NULL;
323
if ((a = array_index(s, *idx)) && *a)
324
e = (*a)->iterate_next;
327
e = s->iterate_list_head;
336
void* pa_idxset_first(pa_idxset *s, uint32_t *idx) {
339
if (!s->iterate_list_head)
343
*idx = s->iterate_list_head->index;
344
return s->iterate_list_head->data;
347
void *pa_idxset_next(pa_idxset *s, uint32_t *idx) {
348
idxset_entry **a, *e = NULL;
352
if ((a = array_index(s, *idx)) && *a)
353
e = (*a)->iterate_next;
359
*idx = PA_IDXSET_INVALID;
364
int pa_idxset_foreach(pa_idxset*s, int (*func)(void *p, uint32_t idx, int *del, void*userdata), void *userdata) {
368
e = s->iterate_list_head;
371
idxset_entry *n = e->iterate_next;
373
r = func(e->data, e->index, &del, userdata);
387
unsigned pa_idxset_size(pa_idxset*s) {
392
int pa_idxset_isempty(pa_idxset *s) {
394
return s->n_entries == 0;