1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77: #include "dbus-hash.h"
78: #include "dbus-internals.h"
79: #include "dbus-mempool.h"
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103: #define REBUILD_MULTIPLIER 3
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121: #define RANDOM_INDEX(table, i) \
122: (((((long) (i))*1103515245) >> (table)->down_shift) & (table)->mask)
123:
124:
125:
126:
127:
128:
129: #define DBUS_SMALL_HASH_TABLE 4
130:
131:
132:
133:
134: typedef struct DBusHashEntry DBusHashEntry;
135:
136:
137:
138:
139:
140:
141:
142: struct DBusHashEntry
143: {
144: DBusHashEntry *next;
145:
146:
147:
148: void *key;
149: void *value;
150: };
151:
152:
153:
154:
155: typedef DBusHashEntry* (* DBusFindEntryFunction) (DBusHashTable *table,
156: void *key,
157: dbus_bool_t create_if_not_found,
158: DBusHashEntry ***bucket,
159: DBusPreallocatedHash *preallocated);
160:
161:
162:
163:
164:
165:
166:
167: struct DBusHashTable {
168: int refcount;
169:
170: DBusHashEntry **buckets;
171:
172:
173:
174: DBusHashEntry *static_buckets[DBUS_SMALL_HASH_TABLE];
175:
176:
177:
178: int n_buckets;
179:
180:
181: int n_entries;
182:
183:
184: int hi_rebuild_size;
185:
186:
187: int lo_rebuild_size;
188:
189:
190: int down_shift;
191:
192:
193:
194: int mask;
195:
196:
197: DBusHashType key_type;
198:
199:
200: DBusFindEntryFunction find_function;
201:
202: DBusFreeFunction free_key_function;
203: DBusFreeFunction free_value_function;
204:
205: DBusMemPool *entry_pool;
206: };
207:
208:
209:
210:
211: typedef struct
212: {
213: DBusHashTable *table;
214: DBusHashEntry **bucket;
215:
216:
217:
218: DBusHashEntry *entry;
219: DBusHashEntry *next_entry;
220: int next_bucket;
221: int n_entries_on_init;
222: } DBusRealHashIter;
223:
224: static DBusHashEntry* find_direct_function (DBusHashTable *table,
225: void *key,
226: dbus_bool_t create_if_not_found,
227: DBusHashEntry ***bucket,
228: DBusPreallocatedHash *preallocated);
229: static DBusHashEntry* find_string_function (DBusHashTable *table,
230: void *key,
231: dbus_bool_t create_if_not_found,
232: DBusHashEntry ***bucket,
233: DBusPreallocatedHash *preallocated);
234: #ifdef DBUS_BUILD_TESTS
235: static DBusHashEntry* find_two_strings_function (DBusHashTable *table,
236: void *key,
237: dbus_bool_t create_if_not_found,
238: DBusHashEntry ***bucket,
239: DBusPreallocatedHash *preallocated);
240: #endif
241: static unsigned int string_hash (const char *str);
242: #ifdef DBUS_BUILD_TESTS
243: static unsigned int two_strings_hash (const char *str);
244: #endif
245: static void rebuild_table (DBusHashTable *table);
246: static DBusHashEntry* alloc_entry (DBusHashTable *table);
247: static void remove_entry (DBusHashTable *table,
248: DBusHashEntry **bucket,
249: DBusHashEntry *entry);
250: static void free_entry (DBusHashTable *table,
251: DBusHashEntry *entry);
252: static void free_entry_data (DBusHashTable *table,
253: DBusHashEntry *entry);
254:
255:
256:
257:
258:
259:
260:
261:
262:
263:
264:
265:
266:
267:
268:
269:
270:
271:
272:
273:
274:
275:
276:
277:
278:
279:
280:
281:
282:
283:
284:
285:
286:
287:
288:
289:
290:
291: DBusHashTable*
292: _dbus_hash_table_new (DBusHashType type,
293: DBusFreeFunction key_free_function,
294: DBusFreeFunction value_free_function)
295: {
296: DBusHashTable *table;
297: DBusMemPool *entry_pool;
298:
299: table = dbus_new0 (DBusHashTable, 1);
300: if (table == NULL)
301: return NULL;
302:
303: entry_pool = _dbus_mem_pool_new (sizeof (DBusHashEntry), TRUE);
304: if (entry_pool == NULL)
305: {
306: dbus_free (table);
307: return NULL;
308: }
309:
310: table->refcount = 1;
311: table->entry_pool = entry_pool;
312:
313: _dbus_assert (DBUS_SMALL_HASH_TABLE == _DBUS_N_ELEMENTS (table->static_buckets));
314:
315: table->buckets = table->static_buckets;
316: table->n_buckets = DBUS_SMALL_HASH_TABLE;
317: table->n_entries = 0;
318: table->hi_rebuild_size = DBUS_SMALL_HASH_TABLE * REBUILD_MULTIPLIER;
319: table->lo_rebuild_size = 0;
320: table->down_shift = 28;
321: table->mask = 3;
322: table->key_type = type;
323:
324: _dbus_assert (table->mask < table->n_buckets);
325:
326: switch (table->key_type)
327: {
328: case DBUS_HASH_INT:
329: case DBUS_HASH_POINTER:
330: case DBUS_HASH_ULONG:
331: table->find_function = find_direct_function;
332: break;
333: case DBUS_HASH_STRING:
334: table->find_function = find_string_function;
335: break;
336: case DBUS_HASH_TWO_STRINGS:
337: #ifdef DBUS_BUILD_TESTS
338: table->find_function = find_two_strings_function;
339: #endif
340: break;
341: default:
342: _dbus_assert_not_reached ("Unknown hash table type");
343: break;
344: }
345:
346: table->free_key_function = key_free_function;
347: table->free_value_function = value_free_function;
348:
349: return table;
350: }
351:
352:
353:
354:
355:
356:
357:
358:
359: DBusHashTable *
360: _dbus_hash_table_ref (DBusHashTable *table)
361: {
362: table->refcount += 1;
363:
364: return table;
365: }
366:
367:
368:
369:
370:
371:
372:
373: void
374: _dbus_hash_table_unref (DBusHashTable *table)
375: {
376: table->refcount -= 1;
377:
378: if (table->refcount == 0)
379: {
380: #if 0
381: DBusHashEntry *entry;
382: DBusHashEntry *next;
383: int i;
384:
385:
386: for (i = 0; i < table->n_buckets; i++)
387: {
388: entry = table->buckets[i];
389: while (entry != NULL)
390: {
391: next = entry->next;
392:
393: free_entry (table, entry);
394:
395: entry = next;
396: }
397: }
398: #else
399: DBusHashEntry *entry;
400: int i;
401:
402:
403: for (i = 0; i < table->n_buckets; i++)
404: {
405: entry = table->buckets[i];
406: while (entry != NULL)
407: {
408: free_entry_data (table, entry);
409:
410: entry = entry->next;
411: }
412: }
413:
414: _dbus_mem_pool_free (table->entry_pool);
415: #endif
416:
417:
418: if (table->buckets != table->static_buckets)
419: dbus_free (table->buckets);
420:
421: dbus_free (table);
422: }
423: }
424:
425:
426:
427:
428:
429:
430: void
431: _dbus_hash_table_remove_all (DBusHashTable *table)
432: {
433: DBusHashIter iter;
434: _dbus_hash_iter_init (table, &iter);
435: while (_dbus_hash_iter_next (&iter))
436: {
437: _dbus_hash_iter_remove_entry(&iter);
438: }
439: }
440:
441: static DBusHashEntry*
442: alloc_entry (DBusHashTable *table)
443: {
444: DBusHashEntry *entry;
445:
446: entry = _dbus_mem_pool_alloc (table->entry_pool);
447:
448: return entry;
449: }
450:
451: static void
452: free_entry_data (DBusHashTable *table,
453: DBusHashEntry *entry)
454: {
455: if (table->free_key_function)
456: (* table->free_key_function) (entry->key);
457: if (table->free_value_function)
458: (* table->free_value_function) (entry->value);
459: }
460:
461: static void
462: free_entry (DBusHashTable *table,
463: DBusHashEntry *entry)
464: {
465: free_entry_data (table, entry);
466: _dbus_mem_pool_dealloc (table->entry_pool, entry);
467: }
468:
469: static void
470: remove_entry (DBusHashTable *table,
471: DBusHashEntry **bucket,
472: DBusHashEntry *entry)
473: {
474: _dbus_assert (table != NULL);
475: _dbus_assert (bucket != NULL);
476: _dbus_assert (*bucket != NULL);
477: _dbus_assert (entry != NULL);
478:
479: if (*bucket == entry)
480: *bucket = entry->next;
481: else
482: {
483: DBusHashEntry *prev;
484: prev = *bucket;
485:
486: while (prev->next != entry)
487: prev = prev->next;
488:
489: _dbus_assert (prev != NULL);
490:
491: prev->next = entry->next;
492: }
493:
494: table->n_entries -= 1;
495: free_entry (table, entry);
496: }
497:
498:
499:
500:
501:
502:
503:
504:
505:
506:
507:
508:
509:
510:
511:
512:
513:
514:
515:
516:
517:
518:
519:
520:
521:
522:
523:
524:
525:
526:
527:
528:
529: void
530: _dbus_hash_iter_init (DBusHashTable *table,
531: DBusHashIter *iter)
532: {
533: DBusRealHashIter *real;
534:
535: _dbus_assert (sizeof (DBusHashIter) == sizeof (DBusRealHashIter));
536:
537: real = (DBusRealHashIter*) iter;
538:
539: real->table = table;
540: real->bucket = NULL;
541: real->entry = NULL;
542: real->next_entry = NULL;
543: real->next_bucket = 0;
544: real->n_entries_on_init = table->n_entries;
545: }
546:
547:
548:
549:
550:
551:
552:
553:
554:
555: dbus_bool_t
556: _dbus_hash_iter_next (DBusHashIter *iter)
557: {
558: DBusRealHashIter *real;
559:
560: _dbus_assert (sizeof (DBusHashIter) == sizeof (DBusRealHashIter));
561:
562: real = (DBusRealHashIter*) iter;
563:
564:
565:
566:
567: _dbus_assert (real->n_entries_on_init >= real->table->n_entries);
568:
569:
570:
571: while (real->next_entry == NULL)
572: {
573: if (real->next_bucket >= real->table->n_buckets)
574: {
575:
576: real->entry = NULL;
577: real->table = NULL;
578: real->bucket = NULL;
579: return FALSE;
580: }
581:
582: real->bucket = &(real->table->buckets[real->next_bucket]);
583: real->next_entry = *(real->bucket);
584: real->next_bucket += 1;
585: }
586:
587: _dbus_assert (real->next_entry != NULL);
588: _dbus_assert (real->bucket != NULL);
589:
590: real->entry = real->next_entry;
591: real->next_entry = real->entry->next;
592:
593: return TRUE;
594: }
595:
596:
597:
598:
599:
600:
601:
602:
603:
604: void
605: _dbus_hash_iter_remove_entry (DBusHashIter *iter)
606: {
607: DBusRealHashIter *real;
608:
609: real = (DBusRealHashIter*) iter;
610:
611: _dbus_assert (real->table != NULL);
612: _dbus_assert (real->entry != NULL);
613: _dbus_assert (real->bucket != NULL);
614:
615: remove_entry (real->table, real->bucket, real->entry);
616:
617: real->entry = NULL;
618: }
619: