idxset

idxset.c

  1 /* $Id: idxset.c 90 2004-07-17 14:12:30Z lennart $ */
  2 
  3 /***
  4   This file is part of polypaudio.
  5  
  6   polypaudio is free software; you can redistribute it and/or modify
  7   it under the terms of the GNU General Public License as published
  8   by the Free Software Foundation; either version 2 of the License,
  9   or (at your option) any later version.
 10  
 11   polypaudio 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.
 15  
 16   You should have received a copy of the GNU General Public License
 17   along with polypaudio; if not, write to the Free Software
 18   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 19   USA.
 20 ***/
 21 
 22 #ifdef HAVE_CONFIG_H
 23 #include <config.h>
 24 #endif
 25 
 26 #include <stdio.h>
 27 #include <assert.h>
 28 #include <stdlib.h>
 29 #include <string.h>
 30 
 31 #include "idxset.h"
 32 
 33 struct idxset_entry {
 34     void *data;
 35     uint32_t index;
 36     unsigned hash_value;
 37 
 38     struct idxset_entry *hash_prev, *hash_next;
 39     struct idxset_entry* iterate_prev, *iterate_next;
 40 };
 41 
 42 struct pa_idxset {
 43     unsigned (*hash_func) (const void *p);
 44     int (*compare_func)(const void *a, const void *b);
 45     
 46     unsigned hash_table_size, n_entries;
 47     struct idxset_entry **hash_table, **array, *iterate_list_head, *iterate_list_tail;
 48     uint32_t index, start_index, array_size;
 49 };
 50 
 51 unsigned pa_idxset_string_hash_func(const void *p) {
 52     unsigned hash = 0;
 53     const char *c;
 54     
 55     for (c = p; *c; c++)
 56         hash = 31 * hash + *c;
 57 
 58     return hash;
 59 }
 60 
 61 int pa_idxset_string_compare_func(const void *a, const void *b) {
 62     return strcmp(a, b);
 63 }
 64 
 65 unsigned pa_idxset_trivial_hash_func(const void *p) {
 66     return (unsigned) p;
 67 }
 68 
 69 int pa_idxset_trivial_compare_func(const void *a, const void *b) {
 70     return a != b;
 71 }
 72 
 73 struct pa_idxset* pa_idxset_new(unsigned (*hash_func) (const void *p), int (*compare_func) (const void*a, const void*b)) {
 74     struct pa_idxset *s;
 75 
 76     s = malloc(sizeof(struct pa_idxset));
 77     assert(s);
 78     s->hash_func = hash_func ? hash_func : pa_idxset_trivial_hash_func;
 79     s->compare_func = compare_func ? compare_func : pa_idxset_trivial_compare_func;
 80     s->hash_table_size = 1023;
 81     s->hash_table = malloc(sizeof(struct idxset_entry*)*s->hash_table_size);
 82     assert(s->hash_table);
 83     memset(s->hash_table, 0, sizeof(struct idxset_entry*)*s->hash_table_size);
 84     s->array = NULL;
 85     s->array_size = 0;
 86     s->index = 0;
 87     s->start_index = 0;
 88     s->n_entries = 0;
 89 
 90     s->iterate_list_head = s->iterate_list_tail = NULL;
 91 
 92     return s;
 93 }
 94 
 95 void pa_idxset_free(struct pa_idxset *s, void (*free_func) (void *p, void *userdata), void *userdata) {
 96     assert(s);
 97 
 98     if (free_func) {
 99         while (s->iterate_list_head) {
100             struct idxset_entry *e = s->iterate_list_head;
101             s->iterate_list_head = s->iterate_list_head->iterate_next;
102 
103             if (free_func)
104                 free_func(e->data, userdata);
105             free(e);
106         }
107     }
108 
109     free(s->hash_table);
110     free(s->array);
111     free(s);
112 }
113 
114 static struct idxset_entry* hash_scan(struct pa_idxset *s, struct idxset_entry* e, void *p) {
115     assert(p);
116 
117     assert(s->compare_func);
118     for (; e; e = e->hash_next)
119         if (s->compare_func(e->data, p) == 0)
120             return e;
121 
122     return NULL;
123 }
124 
125 static void extend_array(struct pa_idxset *s, uint32_t index) {
126     uint32_t i, j, l;
127     struct idxset_entry** n;
128     assert(index >= s->start_index);
129 
130     if (index < s->start_index + s->array_size)
131         return;
132 
133     for (i = 0; i < s->array_size; i++)
134         if (s->array[i])
135             break;
136 
137     l = index - s->start_index - i + 100;
138     n = malloc(sizeof(struct hash_table_entry*)*l);
139     assert(n);
140     memset(n, 0, sizeof(struct hash_table_entry*)*l);
141     
142     for (j = 0; j < s->array_size-i; j++)
143         n[j] = s->array[i+j];
144 
145     free(s->array);
146     
147     s->array = n;
148     s->array_size = l;
149     s->start_index += i;
150 }
151 
152 static struct idxset_entry** array_index(struct pa_idxset*s, uint32_t index) {
153     if (index >= s->start_index + s->array_size)
154         return NULL;
155     
156     if (index < s->start_index)
157         return NULL;
158     
159     return s->array + (index - s->start_index);
160 }
161 
162 int pa_idxset_put(struct pa_idxset*s, void *p, uint32_t *index) {
163     unsigned h;
164     struct idxset_entry *e, **a;
165     assert(s && p);
166 
167     assert(s->hash_func);
168     h = s->hash_func(p) % s->hash_table_size;
169 
170     assert(s->hash_table);
171     if ((e = hash_scan(s, s->hash_table[h], p))) {
172         if (index)
173             *index = e->index;
174         
175         return -1;
176     }
177 
178     e = malloc(sizeof(struct idxset_entry));
179     assert(e);
180 
181     e->data = p;
182     e->index = s->index++;
183     e->hash_value = h;
184 
185     /* Insert into hash table */
186     e->hash_next = s->hash_table[h];
187     e->hash_prev = NULL;
188     if (s->hash_table[h])
189         s->hash_table[h]->hash_prev = e;
190     s->hash_table[h] = e;
191 
192     /* Insert into array */
193     extend_array(s, e->index);
194     a = array_index(s, e->index);
195     assert(a && !*a);
196     *a = e;
197 
198     /* Insert into linked list */
199     e->iterate_next = NULL;
200     e->iterate_prev = s->iterate_list_tail;
201     if (s->iterate_list_tail) {
202         assert(s->iterate_list_head);
203         s->iterate_list_tail->iterate_next = e;
204     } else {
205         assert(!s->iterate_list_head);
206         s->iterate_list_head = e;
207     }
208     s->iterate_list_tail = e;
209     
210     s->n_entries++;
211     assert(s->n_entries >= 1);
212     
213     if (index)
214         *index = e->index;
215 
216     return 0;
217 }
218 
219 void* pa_idxset_get_by_index(struct pa_idxset*s, uint32_t index) {
220     struct idxset_entry **a;
221     assert(s);
222     
223     if (!(a = array_index(s, index)))
224         return NULL;
225 
226     if (!*a)
227         return NULL;
228 
229     return (*a)->data;
230 }
231 
232 void* pa_idxset_get_by_data(struct pa_idxset*s, void *p, uint32_t *index) {
233     unsigned h;
234     struct idxset_entry *e;
235     assert(s && p);
236     
237     assert(s->hash_func);
238     h = s->hash_func(p) % s->hash_table_size;
239 
240     assert(s->hash_table);
241     if (!(e = hash_scan(s, s->hash_table[h], p)))
242         return NULL;
243 
244     if (index)
245         *index = e->index;
246 
247     return e->data;
248 }
249 
250 static void remove_entry(struct pa_idxset *s, struct idxset_entry *e) {
251     struct idxset_entry **a;
252     assert(s && e);
253 
254     /* Remove from array */
255     a = array_index(s, e->index);
256     assert(a && *a && *a == e);
257     *a = NULL;
258     
259     /* Remove from linked list */
260     if (e->iterate_next)
261         e->iterate_next->iterate_prev = e->iterate_prev;
262     else
263         s->iterate_list_tail = e->iterate_prev;
264     
265     if (e->iterate_prev)
266         e->iterate_prev->iterate_next = e->iterate_next;
267     else
268         s->iterate_list_head = e->iterate_next;
269 
270     /* Remove from hash table */
271     if (e->hash_next)
272         e->hash_next->hash_prev = e->hash_prev;
273 
274     if (e->hash_prev)
275         e->hash_prev->hash_next = e->hash_next;
276     else
277         s->hash_table[e->hash_value] = e->hash_next;
278 
279     free(e);
280 
281     assert(s->n_entries >= 1);
282     s->n_entries--;
283 }
284 
285 void* pa_idxset_remove_by_index(struct pa_idxset*s, uint32_t index) {
286     struct idxset_entry **a;
287     void *data;
288     
289     assert(s);
290 
291     if (!(a = array_index(s, index)))
292         return NULL;
293 
294     data = (*a)->data;
295     remove_entry(s, *a);
296     
297     return data; 
298 }
299 
300 void* pa_idxset_remove_by_data(struct pa_idxset*s, void *data, uint32_t *index) {
301     struct idxset_entry *e;
302     unsigned h;
303     
304     assert(s->hash_func);
305     h = s->hash_func(data) % s->hash_table_size;
306 
307     assert(s->hash_table);
308     if (!(e = hash_scan(s, s->hash_table[h], data)))
309         return NULL;
310 
311     data = e->data;
312     if (index)
313         *index = e->index;
314 
315     remove_entry(s, e);
316 
317     return data;
318 }
319 
320 void* pa_idxset_rrobin(struct pa_idxset *s, uint32_t *index) {
321     struct idxset_entry **a, *e = NULL;
322     assert(s && index);
323 
324     if ((a = array_index(s, *index)) && *a)
325         e = (*a)->iterate_next;
326 
327     if (!e)
328         e = s->iterate_list_head;
329 
330     if (!e)
331         return NULL;
332     
333     *index = e->index;
334     return e->data;
335 }
336 
337 void* pa_idxset_first(struct pa_idxset *s, uint32_t *index) {
338     assert(s);
339 
340     if (!s->iterate_list_head)
341         return NULL;
342 
343     if (index)
344         *index = s->iterate_list_head->index;
345     return s->iterate_list_head->data;
346 }
347 
348 void *pa_idxset_next(struct pa_idxset *s, uint32_t *index) {
349     struct idxset_entry **a, *e = NULL;
350     assert(s && index);
351 
352     if ((a = array_index(s, *index)) && *a)
353         e = (*a)->iterate_next;
354     
355     if (e) {
356         *index = e->index;
357         return e->data;
358     } else {
359         *index = PA_IDXSET_INVALID;
360         return NULL;
361     }
362 }
363 
364 
365 int pa_idxset_foreach(struct pa_idxset*s, int (*func)(void *p, uint32_t index, int *del, void*userdata), void *userdata) {
366     struct idxset_entry *e;
367     assert(s && func);
368 
369     e = s->iterate_list_head;
370     while (e) {
371         int del = 0, r;
372         struct idxset_entry *n = e->iterate_next;
373 
374         r = func(e->data, e->index, &del, userdata);
375 
376         if (del)
377             remove_entry(s, e);
378 
379         if (r < 0)
380             return r;
381 
382         e = n;
383     }
384     
385     return 0;
386 }
387 
388 unsigned pa_idxset_ncontents(struct pa_idxset*s) {
389     assert(s);
390     return s->n_entries;
391 }
392 
393 int pa_idxset_isempty(struct pa_idxset *s) {
394     assert(s);
395     return s->n_entries == 0;
396 }
View Code

 

idxset.h

 1 #ifndef fooidxsethfoo
 2 #define fooidxsethfoo
 3 
 4 /* $Id: idxset.h 90 2004-07-17 14:12:30Z lennart $ */
 5 
 6 /***
 7   This file is part of polypaudio.
 8  
 9   polypaudio is free software; you can redistribute it and/or modify
10   it under the terms of the GNU General Public License as published
11   by the Free Software Foundation; either version 2 of the License,
12   or (at your option) any later version.
13  
14   polypaudio 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   General Public License for more details.
18  
19   You should have received a copy of the GNU General Public License
20   along with polypaudio; if not, write to the Free Software
21   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
22   USA.
23 ***/
24 
25 #include <inttypes.h>
26 
27 #define PA_IDXSET_INVALID ((uint32_t) -1)
28 
29 unsigned pa_idxset_trivial_hash_func(const void *p);
30 int pa_idxset_trivial_compare_func(const void *a, const void *b);
31 
32 unsigned pa_idxset_string_hash_func(const void *p);
33 int pa_idxset_string_compare_func(const void *a, const void *b);
34 
35 struct pa_idxset;
36 
37 struct pa_idxset* pa_idxset_new(unsigned (*hash_func) (const void *p), int (*compare_func) (const void*a, const void*b));
38 void pa_idxset_free(struct pa_idxset *s, void (*free_func) (void *p, void *userdata), void *userdata);
39 
40 int pa_idxset_put(struct pa_idxset*s, void *p, uint32_t *index);
41 
42 void* pa_idxset_get_by_index(struct pa_idxset*s, uint32_t index);
43 void* pa_idxset_get_by_data(struct pa_idxset*s, void *p, uint32_t *index);
44 
45 void* pa_idxset_remove_by_index(struct pa_idxset*s, uint32_t index);
46 void* pa_idxset_remove_by_data(struct pa_idxset*s, void *p, uint32_t *index);
47 
48 /* This may be used to iterate through all entries. When called with
49    an invalid index value it returns the first entry, otherwise the
50    next following. The function is best called with *index =
51    PA_IDXSET_VALID first. */
52 void* pa_idxset_rrobin(struct pa_idxset *s, uint32_t *index);
53 
54 /* Return the oldest entry in the idxset */
55 void* pa_idxset_first(struct pa_idxset *s, uint32_t *index);
56 void *pa_idxset_next(struct pa_idxset *s, uint32_t *index);
57 
58 int pa_idxset_foreach(struct pa_idxset*s, int (*func)(void *p, uint32_t index, int *del, void*userdata), void *userdata);
59 
60 unsigned pa_idxset_ncontents(struct pa_idxset*s);
61 int pa_idxset_isempty(struct pa_idxset *s);
62 
63 #endif
View Code

 

posted @ 2020-05-17 13:08  renhl  阅读(74)  评论(0)    收藏  举报