]> code.delx.au - pulseaudio/blob - src/pulsecore/idxset.c
Merge commit 'origin/master' into master-tx
[pulseaudio] / src / pulsecore / idxset.c
1 /***
2 This file is part of PulseAudio.
3
4 Copyright 2004-2008 Lennart Poettering
5 Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
6
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.
11
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.
16
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
20 USA.
21 ***/
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30
31 #include <pulse/xmalloc.h>
32 #include <pulsecore/log.h>
33 #include <pulsecore/flist.h>
34 #include <pulsecore/macro.h>
35
36 #include "idxset.h"
37
38 #define NBUCKETS 127
39
40 struct idxset_entry {
41 uint32_t idx;
42 void *data;
43
44 struct idxset_entry *data_next, *data_previous;
45 struct idxset_entry *index_next, *index_previous;
46 struct idxset_entry *iterate_next, *iterate_previous;
47 };
48
49 struct pa_idxset {
50 pa_hash_func_t hash_func;
51 pa_compare_func_t compare_func;
52
53 uint32_t current_index;
54
55 struct idxset_entry *iterate_list_head, *iterate_list_tail;
56 unsigned n_entries;
57 };
58
59 #define BY_DATA(i) ((struct idxset_entry**) ((uint8_t*) (i) + PA_ALIGN(sizeof(pa_idxset))))
60 #define BY_INDEX(i) (BY_DATA(i) + NBUCKETS)
61
62 PA_STATIC_FLIST_DECLARE(entries, 0, pa_xfree);
63
64 unsigned pa_idxset_string_hash_func(const void *p) {
65 unsigned hash = 0;
66 const char *c;
67
68 for (c = p; *c; c++)
69 hash = 31 * hash + (unsigned) *c;
70
71 return hash;
72 }
73
74 int pa_idxset_string_compare_func(const void *a, const void *b) {
75 return strcmp(a, b);
76 }
77
78 unsigned pa_idxset_trivial_hash_func(const void *p) {
79 return PA_PTR_TO_UINT(p);
80 }
81
82 int pa_idxset_trivial_compare_func(const void *a, const void *b) {
83 return a < b ? -1 : (a > b ? 1 : 0);
84 }
85
86 pa_idxset* pa_idxset_new(pa_hash_func_t hash_func, pa_compare_func_t compare_func) {
87 pa_idxset *s;
88
89 s = pa_xmalloc0(PA_ALIGN(sizeof(pa_idxset)) + NBUCKETS*2*sizeof(struct idxset_entry*));
90
91 s->hash_func = hash_func ? hash_func : pa_idxset_trivial_hash_func;
92 s->compare_func = compare_func ? compare_func : pa_idxset_trivial_compare_func;
93
94 s->current_index = 0;
95 s->n_entries = 0;
96 s->iterate_list_head = s->iterate_list_tail = NULL;
97
98 return s;
99 }
100
101 static void remove_entry(pa_idxset *s, struct idxset_entry *e) {
102 pa_assert(s);
103 pa_assert(e);
104
105 /* Remove from iteration linked list */
106 if (e->iterate_next)
107 e->iterate_next->iterate_previous = e->iterate_previous;
108 else
109 s->iterate_list_tail = e->iterate_previous;
110
111 if (e->iterate_previous)
112 e->iterate_previous->iterate_next = e->iterate_next;
113 else
114 s->iterate_list_head = e->iterate_next;
115
116 /* Remove from data hash table */
117 if (e->data_next)
118 e->data_next->data_previous = e->data_previous;
119
120 if (e->data_previous)
121 e->data_previous->data_next = e->data_next;
122 else {
123 unsigned hash = s->hash_func(e->data) % NBUCKETS;
124 BY_DATA(s)[hash] = e->data_next;
125 }
126
127 /* Remove from index hash table */
128 if (e->index_next)
129 e->index_next->index_previous = e->index_previous;
130
131 if (e->index_previous)
132 e->index_previous->index_next = e->index_next;
133 else
134 BY_INDEX(s)[e->idx % NBUCKETS] = e->index_next;
135
136 if (pa_flist_push(PA_STATIC_FLIST_GET(entries), e) < 0)
137 pa_xfree(e);
138
139 pa_assert(s->n_entries >= 1);
140 s->n_entries--;
141 }
142
143 void pa_idxset_free(pa_idxset *s, pa_free2_cb_t free_cb, void *userdata) {
144 pa_assert(s);
145
146 while (s->iterate_list_head) {
147 void *data = s->iterate_list_head->data;
148
149 remove_entry(s, s->iterate_list_head);
150
151 if (free_cb)
152 free_cb(data, userdata);
153 }
154
155 pa_xfree(s);
156 }
157
158 static struct idxset_entry* data_scan(pa_idxset *s, unsigned hash, const void *p) {
159 struct idxset_entry *e;
160 pa_assert(s);
161 pa_assert(hash < NBUCKETS);
162 pa_assert(p);
163
164 for (e = BY_DATA(s)[hash]; e; e = e->data_next)
165 if (s->compare_func(e->data, p) == 0)
166 return e;
167
168 return NULL;
169 }
170
171 static struct idxset_entry* index_scan(pa_idxset *s, unsigned hash, uint32_t idx) {
172 struct idxset_entry *e;
173 pa_assert(s);
174 pa_assert(hash < NBUCKETS);
175
176 for (e = BY_INDEX(s)[hash]; e; e = e->index_next)
177 if (e->idx == idx)
178 return e;
179
180 return NULL;
181 }
182
183 int pa_idxset_put(pa_idxset*s, void *p, uint32_t *idx) {
184 unsigned hash;
185 struct idxset_entry *e;
186
187 pa_assert(s);
188
189 hash = s->hash_func(p) % NBUCKETS;
190
191 if ((e = data_scan(s, hash, p))) {
192 if (idx)
193 *idx = e->idx;
194
195 return -1;
196 }
197
198 if (!(e = pa_flist_pop(PA_STATIC_FLIST_GET(entries))))
199 e = pa_xnew(struct idxset_entry, 1);
200
201 e->data = p;
202 e->idx = s->current_index++;
203
204 /* Insert into data hash table */
205 e->data_next = BY_DATA(s)[hash];
206 e->data_previous = NULL;
207 if (BY_DATA(s)[hash])
208 BY_DATA(s)[hash]->data_previous = e;
209 BY_DATA(s)[hash] = e;
210
211 hash = e->idx % NBUCKETS;
212
213 /* Insert into index hash table */
214 e->index_next = BY_INDEX(s)[hash];
215 e->index_previous = NULL;
216 if (BY_INDEX(s)[hash])
217 BY_INDEX(s)[hash]->index_previous = e;
218 BY_INDEX(s)[hash] = e;
219
220 /* Insert into iteration list */
221 e->iterate_previous = s->iterate_list_tail;
222 e->iterate_next = NULL;
223 if (s->iterate_list_tail) {
224 pa_assert(s->iterate_list_head);
225 s->iterate_list_tail->iterate_next = e;
226 } else {
227 pa_assert(!s->iterate_list_head);
228 s->iterate_list_head = e;
229 }
230 s->iterate_list_tail = e;
231
232 s->n_entries++;
233 pa_assert(s->n_entries >= 1);
234
235 if (idx)
236 *idx = e->idx;
237
238 return 0;
239 }
240
241 void* pa_idxset_get_by_index(pa_idxset*s, uint32_t idx) {
242 unsigned hash;
243 struct idxset_entry *e;
244
245 pa_assert(s);
246
247 hash = idx % NBUCKETS;
248
249 if (!(e = index_scan(s, hash, idx)))
250 return NULL;
251
252 return e->data;
253 }
254
255 void* pa_idxset_get_by_data(pa_idxset*s, const void *p, uint32_t *idx) {
256 unsigned hash;
257 struct idxset_entry *e;
258
259 pa_assert(s);
260
261 hash = s->hash_func(p) % NBUCKETS;
262
263 if (!(e = data_scan(s, hash, p)))
264 return NULL;
265
266 if (idx)
267 *idx = e->idx;
268
269 return e->data;
270 }
271
272 void* pa_idxset_remove_by_index(pa_idxset*s, uint32_t idx) {
273 struct idxset_entry *e;
274 unsigned hash;
275 void *data;
276
277 pa_assert(s);
278
279 hash = idx % NBUCKETS;
280
281 if (!(e = index_scan(s, hash, idx)))
282 return NULL;
283
284 data = e->data;
285 remove_entry(s, e);
286
287 return data;
288 }
289
290 void* pa_idxset_remove_by_data(pa_idxset*s, const void *data, uint32_t *idx) {
291 struct idxset_entry *e;
292 unsigned hash;
293 void *r;
294
295 pa_assert(s);
296
297 hash = s->hash_func(data) % NBUCKETS;
298
299 if (!(e = data_scan(s, hash, data)))
300 return NULL;
301
302 r = e->data;
303
304 if (idx)
305 *idx = e->idx;
306
307 remove_entry(s, e);
308
309 return r;
310 }
311
312 void* pa_idxset_rrobin(pa_idxset *s, uint32_t *idx) {
313 unsigned hash;
314 struct idxset_entry *e;
315
316 pa_assert(s);
317 pa_assert(idx);
318
319 hash = *idx % NBUCKETS;
320
321 e = index_scan(s, hash, *idx);
322
323 if (e && e->iterate_next)
324 e = e->iterate_next;
325 else
326 e = s->iterate_list_head;
327
328 if (!e)
329 return NULL;
330
331 *idx = e->idx;
332 return e->data;
333 }
334
335 void *pa_idxset_iterate(pa_idxset *s, void **state, uint32_t *idx) {
336 struct idxset_entry *e;
337
338 pa_assert(s);
339 pa_assert(state);
340
341 if (*state == (void*) -1)
342 goto at_end;
343
344 if ((!*state && !s->iterate_list_head))
345 goto at_end;
346
347 e = *state ? *state : s->iterate_list_head;
348
349 if (e->iterate_next)
350 *state = e->iterate_next;
351 else
352 *state = (void*) -1;
353
354 if (idx)
355 *idx = e->idx;
356
357 return e->data;
358
359 at_end:
360 *state = (void *) -1;
361
362 if (idx)
363 *idx = PA_IDXSET_INVALID;
364
365 return NULL;
366 }
367
368 void* pa_idxset_steal_first(pa_idxset *s, uint32_t *idx) {
369 void *data;
370
371 pa_assert(s);
372
373 if (!s->iterate_list_head)
374 return NULL;
375
376 data = s->iterate_list_head->data;
377
378 if (idx)
379 *idx = s->iterate_list_head->idx;
380
381 remove_entry(s, s->iterate_list_head);
382
383 return data;
384 }
385
386 void* pa_idxset_first(pa_idxset *s, uint32_t *idx) {
387 pa_assert(s);
388
389 if (!s->iterate_list_head) {
390 if (idx)
391 *idx = PA_IDXSET_INVALID;
392 return NULL;
393 }
394
395 if (idx)
396 *idx = s->iterate_list_head->idx;
397
398 return s->iterate_list_head->data;
399 }
400
401 void *pa_idxset_next(pa_idxset *s, uint32_t *idx) {
402 struct idxset_entry *e;
403 unsigned hash;
404
405 pa_assert(s);
406 pa_assert(idx);
407
408 if (*idx == PA_IDXSET_INVALID)
409 return NULL;
410
411 hash = *idx % NBUCKETS;
412
413 if ((e = index_scan(s, hash, *idx))) {
414
415 e = e->iterate_next;
416
417 if (e) {
418 *idx = e->idx;
419 return e->data;
420 } else {
421 *idx = PA_IDXSET_INVALID;
422 return NULL;
423 }
424
425 } else {
426
427 /* If the entry passed doesn't exist anymore we try to find
428 * the next following */
429
430 for ((*idx)++; *idx < s->current_index; (*idx)++) {
431
432 hash = *idx % NBUCKETS;
433
434 if ((e = index_scan(s, hash, *idx))) {
435 *idx = e->idx;
436 return e->data;
437 }
438 }
439
440 *idx = PA_IDXSET_INVALID;
441 return NULL;
442 }
443 }
444
445 unsigned pa_idxset_size(pa_idxset*s) {
446 pa_assert(s);
447
448 return s->n_entries;
449 }
450
451 pa_bool_t pa_idxset_isempty(pa_idxset *s) {
452 pa_assert(s);
453
454 return s->n_entries == 0;
455 }
456
457 pa_idxset *pa_idxset_copy(pa_idxset *s) {
458 pa_idxset *copy;
459 struct idxset_entry *i;
460
461 pa_assert(s);
462
463 copy = pa_idxset_new(s->hash_func, s->compare_func);
464
465 for (i = s->iterate_list_head; i; i = i->iterate_next)
466 pa_idxset_put(copy, i->data, NULL);
467
468 return copy;
469 }