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 }
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
浙公网安备 33010602011771号