2 This file is part of PulseAudio.
4 Copyright 2004-2008 Lennart Poettering
5 Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
7 PulseAudio is free software; you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as
9 published by the Free Software Foundation; either version 2.1 of the
10 License, or (at your option) any later version.
12 PulseAudio is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public
18 License along with PulseAudio; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
31 #include <pulse/xmalloc.h>
32 #include <pulsecore/flist.h>
33 #include <pulsecore/macro.h>
43 struct idxset_entry
*data_next
, *data_previous
;
44 struct idxset_entry
*index_next
, *index_previous
;
45 struct idxset_entry
*iterate_next
, *iterate_previous
;
49 pa_hash_func_t hash_func
;
50 pa_compare_func_t compare_func
;
52 uint32_t current_index
;
54 struct idxset_entry
*iterate_list_head
, *iterate_list_tail
;
58 #define BY_DATA(i) ((struct idxset_entry**) ((uint8_t*) (i) + PA_ALIGN(sizeof(pa_idxset))))
59 #define BY_INDEX(i) (BY_DATA(i) + NBUCKETS)
61 PA_STATIC_FLIST_DECLARE(entries
, 0, pa_xfree
);
63 unsigned pa_idxset_string_hash_func(const void *p
) {
68 hash
= 31 * hash
+ (unsigned) *c
;
73 int pa_idxset_string_compare_func(const void *a
, const void *b
) {
77 unsigned pa_idxset_trivial_hash_func(const void *p
) {
78 return PA_PTR_TO_UINT(p
);
81 int pa_idxset_trivial_compare_func(const void *a
, const void *b
) {
82 return a
< b
? -1 : (a
> b
? 1 : 0);
85 pa_idxset
* pa_idxset_new(pa_hash_func_t hash_func
, pa_compare_func_t compare_func
) {
88 s
= pa_xmalloc0(PA_ALIGN(sizeof(pa_idxset
)) + NBUCKETS
*2*sizeof(struct idxset_entry
*));
90 s
->hash_func
= hash_func
? hash_func
: pa_idxset_trivial_hash_func
;
91 s
->compare_func
= compare_func
? compare_func
: pa_idxset_trivial_compare_func
;
95 s
->iterate_list_head
= s
->iterate_list_tail
= NULL
;
100 static void remove_entry(pa_idxset
*s
, struct idxset_entry
*e
) {
104 /* Remove from iteration linked list */
106 e
->iterate_next
->iterate_previous
= e
->iterate_previous
;
108 s
->iterate_list_tail
= e
->iterate_previous
;
110 if (e
->iterate_previous
)
111 e
->iterate_previous
->iterate_next
= e
->iterate_next
;
113 s
->iterate_list_head
= e
->iterate_next
;
115 /* Remove from data hash table */
117 e
->data_next
->data_previous
= e
->data_previous
;
119 if (e
->data_previous
)
120 e
->data_previous
->data_next
= e
->data_next
;
122 unsigned hash
= s
->hash_func(e
->data
) % NBUCKETS
;
123 BY_DATA(s
)[hash
] = e
->data_next
;
126 /* Remove from index hash table */
128 e
->index_next
->index_previous
= e
->index_previous
;
130 if (e
->index_previous
)
131 e
->index_previous
->index_next
= e
->index_next
;
133 BY_INDEX(s
)[e
->idx
% NBUCKETS
] = e
->index_next
;
135 if (pa_flist_push(PA_STATIC_FLIST_GET(entries
), e
) < 0)
138 pa_assert(s
->n_entries
>= 1);
142 void pa_idxset_free(pa_idxset
*s
, pa_free2_cb_t free_cb
, void *userdata
) {
145 while (s
->iterate_list_head
) {
146 void *data
= s
->iterate_list_head
->data
;
148 remove_entry(s
, s
->iterate_list_head
);
151 free_cb(data
, userdata
);
157 static struct idxset_entry
* data_scan(pa_idxset
*s
, unsigned hash
, const void *p
) {
158 struct idxset_entry
*e
;
160 pa_assert(hash
< NBUCKETS
);
163 for (e
= BY_DATA(s
)[hash
]; e
; e
= e
->data_next
)
164 if (s
->compare_func(e
->data
, p
) == 0)
170 static struct idxset_entry
* index_scan(pa_idxset
*s
, unsigned hash
, uint32_t idx
) {
171 struct idxset_entry
*e
;
173 pa_assert(hash
< NBUCKETS
);
175 for (e
= BY_INDEX(s
)[hash
]; e
; e
= e
->index_next
)
182 int pa_idxset_put(pa_idxset
*s
, void *p
, uint32_t *idx
) {
184 struct idxset_entry
*e
;
188 hash
= s
->hash_func(p
) % NBUCKETS
;
190 if ((e
= data_scan(s
, hash
, p
))) {
197 if (!(e
= pa_flist_pop(PA_STATIC_FLIST_GET(entries
))))
198 e
= pa_xnew(struct idxset_entry
, 1);
201 e
->idx
= s
->current_index
++;
203 /* Insert into data hash table */
204 e
->data_next
= BY_DATA(s
)[hash
];
205 e
->data_previous
= NULL
;
206 if (BY_DATA(s
)[hash
])
207 BY_DATA(s
)[hash
]->data_previous
= e
;
208 BY_DATA(s
)[hash
] = e
;
210 hash
= e
->idx
% NBUCKETS
;
212 /* Insert into index hash table */
213 e
->index_next
= BY_INDEX(s
)[hash
];
214 e
->index_previous
= NULL
;
215 if (BY_INDEX(s
)[hash
])
216 BY_INDEX(s
)[hash
]->index_previous
= e
;
217 BY_INDEX(s
)[hash
] = e
;
219 /* Insert into iteration list */
220 e
->iterate_previous
= s
->iterate_list_tail
;
221 e
->iterate_next
= NULL
;
222 if (s
->iterate_list_tail
) {
223 pa_assert(s
->iterate_list_head
);
224 s
->iterate_list_tail
->iterate_next
= e
;
226 pa_assert(!s
->iterate_list_head
);
227 s
->iterate_list_head
= e
;
229 s
->iterate_list_tail
= e
;
232 pa_assert(s
->n_entries
>= 1);
240 void* pa_idxset_get_by_index(pa_idxset
*s
, uint32_t idx
) {
242 struct idxset_entry
*e
;
246 hash
= idx
% NBUCKETS
;
248 if (!(e
= index_scan(s
, hash
, idx
)))
254 void* pa_idxset_get_by_data(pa_idxset
*s
, const void *p
, uint32_t *idx
) {
256 struct idxset_entry
*e
;
260 hash
= s
->hash_func(p
) % NBUCKETS
;
262 if (!(e
= data_scan(s
, hash
, p
)))
271 void* pa_idxset_remove_by_index(pa_idxset
*s
, uint32_t idx
) {
272 struct idxset_entry
*e
;
278 hash
= idx
% NBUCKETS
;
280 if (!(e
= index_scan(s
, hash
, idx
)))
289 void* pa_idxset_remove_by_data(pa_idxset
*s
, const void *data
, uint32_t *idx
) {
290 struct idxset_entry
*e
;
296 hash
= s
->hash_func(data
) % NBUCKETS
;
298 if (!(e
= data_scan(s
, hash
, data
)))
311 void* pa_idxset_rrobin(pa_idxset
*s
, uint32_t *idx
) {
313 struct idxset_entry
*e
;
318 hash
= *idx
% NBUCKETS
;
320 e
= index_scan(s
, hash
, *idx
);
322 if (e
&& e
->iterate_next
)
325 e
= s
->iterate_list_head
;
334 void *pa_idxset_iterate(pa_idxset
*s
, void **state
, uint32_t *idx
) {
335 struct idxset_entry
*e
;
340 if (*state
== (void*) -1)
343 if ((!*state
&& !s
->iterate_list_head
))
346 e
= *state
? *state
: s
->iterate_list_head
;
349 *state
= e
->iterate_next
;
359 *state
= (void *) -1;
362 *idx
= PA_IDXSET_INVALID
;
367 void* pa_idxset_steal_first(pa_idxset
*s
, uint32_t *idx
) {
372 if (!s
->iterate_list_head
)
375 data
= s
->iterate_list_head
->data
;
378 *idx
= s
->iterate_list_head
->idx
;
380 remove_entry(s
, s
->iterate_list_head
);
385 void* pa_idxset_first(pa_idxset
*s
, uint32_t *idx
) {
388 if (!s
->iterate_list_head
) {
390 *idx
= PA_IDXSET_INVALID
;
395 *idx
= s
->iterate_list_head
->idx
;
397 return s
->iterate_list_head
->data
;
400 void *pa_idxset_next(pa_idxset
*s
, uint32_t *idx
) {
401 struct idxset_entry
*e
;
407 if (*idx
== PA_IDXSET_INVALID
)
410 hash
= *idx
% NBUCKETS
;
412 if ((e
= index_scan(s
, hash
, *idx
))) {
420 *idx
= PA_IDXSET_INVALID
;
426 /* If the entry passed doesn't exist anymore we try to find
427 * the next following */
429 for ((*idx
)++; *idx
< s
->current_index
; (*idx
)++) {
431 hash
= *idx
% NBUCKETS
;
433 if ((e
= index_scan(s
, hash
, *idx
))) {
439 *idx
= PA_IDXSET_INVALID
;
444 unsigned pa_idxset_size(pa_idxset
*s
) {
450 pa_bool_t
pa_idxset_isempty(pa_idxset
*s
) {
453 return s
->n_entries
== 0;
456 pa_idxset
*pa_idxset_copy(pa_idxset
*s
) {
458 struct idxset_entry
*i
;
462 copy
= pa_idxset_new(s
->hash_func
, s
->compare_func
);
464 for (i
= s
->iterate_list_head
; i
; i
= i
->iterate_next
)
465 pa_idxset_put(copy
, i
->data
, NULL
);