1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2 /* dbus-hash.c Generic hash table utility (internal to D-Bus implementation)
3 *
4 * Copyright (C) 2002 Red Hat, Inc.
5 * Copyright (c) 1991-1993 The Regents of the University of California.
6 * Copyright (c) 1994 Sun Microsystems, Inc.
7 *
8 * Hash table implementation based on generic/tclHash.c from the Tcl
9 * source code. The original Tcl license applies to portions of the
10 * code from tclHash.c; the Tcl license follows this standad D-Bus
11 * license information.
12 *
13 * Licensed under the Academic Free License version 2.1
14 *
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
19 *
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
28 *
29 */
30 /*
31 * The following copyright applies to code from the Tcl distribution.
32 *
33 * Copyright (c) 1991-1993 The Regents of the University of California.
34 * Copyright (c) 1994 Sun Microsystems, Inc.
35 *
36 * This software is copyrighted by the Regents of the University of
37 * California, Sun Microsystems, Inc., Scriptics Corporation, and
38 * other parties. The following terms apply to all files associated
39 * with the software unless explicitly disclaimed in individual files.
40 *
41 * The authors hereby grant permission to use, copy, modify,
42 * distribute, and license this software and its documentation for any
43 * purpose, provided that existing copyright notices are retained in
44 * all copies and that this notice is included verbatim in any
45 * distributions. No written agreement, license, or royalty fee is
46 * required for any of the authorized uses. Modifications to this
47 * software may be copyrighted by their authors and need not follow
48 * the licensing terms described here, provided that the new terms are
49 * clearly indicated on the first page of each file where they apply.
50 *
51 * IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY
52 * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
53 * DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION,
54 * OR ANY DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED
55 * OF THE POSSIBILITY OF SUCH DAMAGE.
56 *
57 * THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
58 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
59 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
60 * NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS,
61 * AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE
62 * MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
63 *
64 * GOVERNMENT USE: If you are acquiring this software on behalf of the
65 * U.S. government, the Government shall have only "Restricted Rights"
66 * in the software and related documentation as defined in the Federal
67 * Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you
68 * are acquiring the software on behalf of the Department of Defense,
69 * the software shall be classified as "Commercial Computer Software"
70 * and the Government shall have only "Restricted Rights" as defined
71 * in Clause 252.227-7013 (c) (1) of DFARs. Notwithstanding the
72 * foregoing, the authors grant the U.S. Government and others acting
73 * in its behalf permission to use and distribute the software in
74 * accordance with the terms specified in this license.
75 */
76
77 #include <config.h>
78 #include "dbus-hash.h"
79 #include "dbus-internals.h"
80 #include "dbus-mempool.h"
81
82 /**
83 * @defgroup DBusHashTable Hash table
84 * @ingroup DBusInternals
85 * @brief DBusHashTable data structure
86 *
87 * Types and functions related to DBusHashTable.
88 */
89
90 /**
91 * @defgroup DBusHashTableInternals Hash table implementation details
92 * @ingroup DBusInternals
93 * @brief DBusHashTable implementation details
94 *
95 * The guts of DBusHashTable.
96 *
97 * @{
98 */
99
100 /**
101 * When there are this many entries per bucket, on average, rebuild
102 * the hash table to make it larger.
103 */
104 #define REBUILD_MULTIPLIER 3
105
106 /**
107 * Takes a preliminary integer hash value and produces an index into a
108 * hash tables bucket list. The idea is to make it so that
109 * preliminary values that are arbitrarily similar will end up in
110 * different buckets. The hash function was taken from a
111 * random-number generator. (This is used to hash integers.)
112 *
113 * The down_shift drops off the high bits of the hash index, and
114 * decreases as we increase the number of hash buckets (to keep more
115 * range in the hash index). The mask also strips high bits and strips
116 * fewer high bits as the number of hash buckets increases.
117 * I don't understand two things: why is the initial downshift 28
118 * to keep 4 bits when the initial mask is 011 to keep 2 bits,
119 * and why do we have both a mask and a downshift?
120 *
121 */
122 #define RANDOM_INDEX(table, i) \
123 (((((intptr_t) (i))*1103515245) >> (table)->down_shift) & (table)->mask)
124
125 /**
126 * Initial number of buckets in hash table (hash table statically
127 * allocates its buckets for this size and below).
128 * The initial mask has to be synced to this.
129 */
130 #define DBUS_SMALL_HASH_TABLE 4
131
132 /**
133 * Typedef for DBusHashEntry
134 */
135 typedef struct DBusHashEntry DBusHashEntry;
136
137 /**
138 * @brief Internal representation of a hash entry.
139 *
140 * A single entry (key-value pair) in the hash table.
141 * Internal to hash table implementation.
142 */
143 struct DBusHashEntry
144 {
145 DBusHashEntry *next; /**< Pointer to next entry in this
146 * hash bucket, or #NULL for end of
147 * chain.
148 */
149 void *key; /**< Hash key */
150 void *value; /**< Hash value */
151 };
152
153 /**
154 * Function used to find and optionally create a hash entry.
155 */
156 typedef DBusHashEntry* (* DBusFindEntryFunction) (DBusHashTable *table,
157 void *key,
158 dbus_bool_t create_if_not_found,
159 DBusHashEntry ***bucket,
160 DBusPreallocatedHash *preallocated);
161
162 /**
163 * @brief Internals of DBusHashTable.
164 *
165 * Hash table internals. Hash tables are opaque objects, they must be
166 * used via accessor functions.
167 */
168 struct DBusHashTable {
169 int refcount; /**< Reference count */
170
171 DBusHashEntry **buckets; /**< Pointer to bucket array. Each
172 * element points to first entry in
173 * bucket's hash chain, or #NULL.
174 */
175 DBusHashEntry *static_buckets[DBUS_SMALL_HASH_TABLE];
176 /**< Bucket array used for small tables
177 * (to avoid mallocs and frees).
178 */
179 int n_buckets; /**< Total number of buckets allocated
180 * at **buckets.
181 */
182 int n_entries; /**< Total number of entries present
183 * in table.
184 */
185 int hi_rebuild_size; /**< Enlarge table when n_entries gets
186 * to be this large.
187 */
188 int lo_rebuild_size; /**< Shrink table when n_entries gets
189 * below this.
190 */
191 int down_shift; /**< Shift count used in hashing
192 * function. Designed to use high-
193 * order bits of randomized keys.
194 */
195 int mask; /**< Mask value used in hashing
196 * function.
197 */
198 DBusHashType key_type; /**< Type of keys used in this table */
199
200
201 DBusFindEntryFunction find_function; /**< Function for finding entries */
202
203 DBusFreeFunction free_key_function; /**< Function to free keys */
204 DBusFreeFunction free_value_function; /**< Function to free values */
205
206 DBusMemPool *entry_pool; /**< Memory pool for hash entries */
207 };
208
209 /**
210 * @brief Internals of DBusHashIter.
211 */
212 typedef struct
213 {
214 DBusHashTable *table; /**< Pointer to table containing entry. */
215 DBusHashEntry **bucket; /**< Pointer to bucket that points to
216 * first entry in this entry's chain:
217 * used for deleting the entry.
218 */
219 DBusHashEntry *entry; /**< Current hash entry */
220 DBusHashEntry *next_entry; /**< Next entry to be iterated onto in current bucket */
221 int next_bucket; /**< index of next bucket */
222 int n_entries_on_init; /**< used to detect table resize since initialization */
223 } DBusRealHashIter;
224
225 static DBusHashEntry* find_direct_function (DBusHashTable *table,
226 void *key,
227 dbus_bool_t create_if_not_found,
228 DBusHashEntry ***bucket,
229 DBusPreallocatedHash *preallocated);
230 static DBusHashEntry* find_string_function (DBusHashTable *table,
231 void *key,
232 dbus_bool_t create_if_not_found,
233 DBusHashEntry ***bucket,
234 DBusPreallocatedHash *preallocated);
235 #ifdef DBUS_BUILD_TESTS
236 static DBusHashEntry* find_two_strings_function (DBusHashTable *table,
237 void *key,
238 dbus_bool_t create_if_not_found,
239 DBusHashEntry ***bucket,
240 DBusPreallocatedHash *preallocated);
241 #endif
242 static unsigned int string_hash (const char *str);
243 #ifdef DBUS_BUILD_TESTS
244 static unsigned int two_strings_hash (const char *str);
245 #endif
246 static void rebuild_table (DBusHashTable *table);
247 static DBusHashEntry* alloc_entry (DBusHashTable *table);
248 static void remove_entry (DBusHashTable *table,
249 DBusHashEntry **bucket,
250 DBusHashEntry *entry);
251 static void free_entry (DBusHashTable *table,
252 DBusHashEntry *entry);
253 static void free_entry_data (DBusHashTable *table,
254 DBusHashEntry *entry);
255
256
257 /** @} */
258
259 /**
260 * @addtogroup DBusHashTable
261 * @{
262 */
263
264 /**
265 * @typedef DBusHashIter
266 *
267 * Public opaque hash table iterator object.
268 */
269
270 /**
271 * @typedef DBusHashTable
272 *
273 * Public opaque hash table object.
274 */
275
276 /**
277 * @typedef DBusHashType
278 *
279 * Indicates the type of a key in the hash table.
280 */
281
282 /**
283 * Constructs a new hash table. Should be freed with
284 * _dbus_hash_table_unref(). If memory cannot be
285 * allocated for the hash table, returns #NULL.
286 *
287 * @param type the type of hash key to use.
288 * @param key_free_function function to free hash keys.
289 * @param value_free_function function to free hash values.
290 * @returns a new DBusHashTable or #NULL if no memory.
291 */
292 DBusHashTable*
_dbus_hash_table_new(DBusHashType type,DBusFreeFunction key_free_function,DBusFreeFunction value_free_function)293 _dbus_hash_table_new (DBusHashType type,
294 DBusFreeFunction key_free_function,
295 DBusFreeFunction value_free_function)
296 {
297 DBusHashTable *table;
298 DBusMemPool *entry_pool;
299
300 table = dbus_new0 (DBusHashTable, 1);
301 if (table == NULL)
302 return NULL;
303
304 entry_pool = _dbus_mem_pool_new (sizeof (DBusHashEntry), TRUE);
305 if (entry_pool == NULL)
306 {
307 dbus_free (table);
308 return NULL;
309 }
310
311 table->refcount = 1;
312 table->entry_pool = entry_pool;
313
314 _dbus_assert (DBUS_SMALL_HASH_TABLE == _DBUS_N_ELEMENTS (table->static_buckets));
315
316 table->buckets = table->static_buckets;
317 table->n_buckets = DBUS_SMALL_HASH_TABLE;
318 table->n_entries = 0;
319 table->hi_rebuild_size = DBUS_SMALL_HASH_TABLE * REBUILD_MULTIPLIER;
320 table->lo_rebuild_size = 0;
321 table->down_shift = 28;
322 table->mask = 3;
323 table->key_type = type;
324
325 _dbus_assert (table->mask < table->n_buckets);
326
327 switch (table->key_type)
328 {
329 case DBUS_HASH_INT:
330 case DBUS_HASH_POINTER:
331 case DBUS_HASH_UINTPTR:
332 table->find_function = find_direct_function;
333 break;
334 case DBUS_HASH_STRING:
335 table->find_function = find_string_function;
336 break;
337 case DBUS_HASH_TWO_STRINGS:
338 #ifdef DBUS_BUILD_TESTS
339 table->find_function = find_two_strings_function;
340 #endif
341 break;
342 default:
343 _dbus_assert_not_reached ("Unknown hash table type");
344 break;
345 }
346
347 table->free_key_function = key_free_function;
348 table->free_value_function = value_free_function;
349
350 return table;
351 }
352
353
354 /**
355 * Increments the reference count for a hash table.
356 *
357 * @param table the hash table to add a reference to.
358 * @returns the hash table.
359 */
360 DBusHashTable *
_dbus_hash_table_ref(DBusHashTable * table)361 _dbus_hash_table_ref (DBusHashTable *table)
362 {
363 table->refcount += 1;
364
365 return table;
366 }
367
368 /**
369 * Decrements the reference count for a hash table,
370 * freeing the hash table if the count reaches zero.
371 *
372 * @param table the hash table to remove a reference from.
373 */
374 void
_dbus_hash_table_unref(DBusHashTable * table)375 _dbus_hash_table_unref (DBusHashTable *table)
376 {
377 table->refcount -= 1;
378
379 if (table->refcount == 0)
380 {
381 #if 0
382 DBusHashEntry *entry;
383 DBusHashEntry *next;
384 int i;
385
386 /* Free the entries in the table. */
387 for (i = 0; i < table->n_buckets; i++)
388 {
389 entry = table->buckets[i];
390 while (entry != NULL)
391 {
392 next = entry->next;
393
394 free_entry (table, entry);
395
396 entry = next;
397 }
398 }
399 #else
400 DBusHashEntry *entry;
401 int i;
402
403 /* Free the entries in the table. */
404 for (i = 0; i < table->n_buckets; i++)
405 {
406 entry = table->buckets[i];
407 while (entry != NULL)
408 {
409 free_entry_data (table, entry);
410
411 entry = entry->next;
412 }
413 }
414 /* We can do this very quickly with memory pools ;-) */
415 _dbus_mem_pool_free (table->entry_pool);
416 #endif
417
418 /* Free the bucket array, if it was dynamically allocated. */
419 if (table->buckets != table->static_buckets)
420 dbus_free (table->buckets);
421
422 dbus_free (table);
423 }
424 }
425
426 /**
427 * Removed all entries from a hash table.
428 *
429 * @param table the hash table to remove all entries from.
430 */
431 void
_dbus_hash_table_remove_all(DBusHashTable * table)432 _dbus_hash_table_remove_all (DBusHashTable *table)
433 {
434 DBusHashIter iter;
435 _dbus_hash_iter_init (table, &iter);
436 while (_dbus_hash_iter_next (&iter))
437 {
438 _dbus_hash_iter_remove_entry(&iter);
439 }
440 }
441
442 static DBusHashEntry*
alloc_entry(DBusHashTable * table)443 alloc_entry (DBusHashTable *table)
444 {
445 DBusHashEntry *entry;
446
447 entry = _dbus_mem_pool_alloc (table->entry_pool);
448
449 return entry;
450 }
451
452 static void
free_entry_data(DBusHashTable * table,DBusHashEntry * entry)453 free_entry_data (DBusHashTable *table,
454 DBusHashEntry *entry)
455 {
456 if (table->free_key_function)
457 (* table->free_key_function) (entry->key);
458 if (table->free_value_function)
459 (* table->free_value_function) (entry->value);
460 }
461
462 static void
free_entry(DBusHashTable * table,DBusHashEntry * entry)463 free_entry (DBusHashTable *table,
464 DBusHashEntry *entry)
465 {
466 free_entry_data (table, entry);
467 _dbus_mem_pool_dealloc (table->entry_pool, entry);
468 }
469
470 static void
remove_entry(DBusHashTable * table,DBusHashEntry ** bucket,DBusHashEntry * entry)471 remove_entry (DBusHashTable *table,
472 DBusHashEntry **bucket,
473 DBusHashEntry *entry)
474 {
475 _dbus_assert (table != NULL);
476 _dbus_assert (bucket != NULL);
477 _dbus_assert (*bucket != NULL);
478 _dbus_assert (entry != NULL);
479
480 if (*bucket == entry)
481 *bucket = entry->next;
482 else
483 {
484 DBusHashEntry *prev;
485 prev = *bucket;
486
487 while (prev->next != entry)
488 prev = prev->next;
489
490 _dbus_assert (prev != NULL);
491
492 prev->next = entry->next;
493 }
494
495 table->n_entries -= 1;
496 free_entry (table, entry);
497 }
498
499 /**
500 * Initializes a hash table iterator. To iterate over all entries in a
501 * hash table, use the following code (the printf assumes a hash
502 * from strings to strings obviously):
503 *
504 * @code
505 * DBusHashIter iter;
506 *
507 * _dbus_hash_iter_init (table, &iter);
508 * while (_dbus_hash_iter_next (&iter))
509 * {
510 * printf ("The first key is %s and value is %s\n",
511 * _dbus_hash_iter_get_string_key (&iter),
512 * _dbus_hash_iter_get_value (&iter));
513 * }
514 *
515 *
516 * @endcode
517 *
518 * The iterator is initialized pointing "one before" the first hash
519 * entry. The first call to _dbus_hash_iter_next() moves it onto
520 * the first valid entry or returns #FALSE if the hash table is
521 * empty. Subsequent calls move to the next valid entry or return
522 * #FALSE if there are no more entries.
523 *
524 * Note that it is guaranteed to be safe to remove a hash entry during
525 * iteration, but it is not safe to add a hash entry.
526 *
527 * @param table the hash table to iterate over.
528 * @param iter the iterator to initialize.
529 */
530 void
_dbus_hash_iter_init(DBusHashTable * table,DBusHashIter * iter)531 _dbus_hash_iter_init (DBusHashTable *table,
532 DBusHashIter *iter)
533 {
534 DBusRealHashIter *real;
535
536 _dbus_assert (sizeof (DBusHashIter) == sizeof (DBusRealHashIter));
537
538 real = (DBusRealHashIter*) iter;
539
540 real->table = table;
541 real->bucket = NULL;
542 real->entry = NULL;
543 real->next_entry = NULL;
544 real->next_bucket = 0;
545 real->n_entries_on_init = table->n_entries;
546 }
547
548 /**
549 * Move the hash iterator forward one step, to the next hash entry.
550 * The documentation for _dbus_hash_iter_init() explains in more
551 * detail.
552 *
553 * @param iter the iterator to move forward.
554 * @returns #FALSE if there are no more entries to move to.
555 */
556 dbus_bool_t
_dbus_hash_iter_next(DBusHashIter * iter)557 _dbus_hash_iter_next (DBusHashIter *iter)
558 {
559 DBusRealHashIter *real;
560
561 _dbus_assert (sizeof (DBusHashIter) == sizeof (DBusRealHashIter));
562
563 real = (DBusRealHashIter*) iter;
564
565 /* if this assertion failed someone probably added hash entries
566 * during iteration, which is bad.
567 */
568 _dbus_assert (real->n_entries_on_init >= real->table->n_entries);
569
570 /* Remember that real->entry may have been deleted */
571
572 while (real->next_entry == NULL)
573 {
574 if (real->next_bucket >= real->table->n_buckets)
575 {
576 /* invalidate iter and return false */
577 real->entry = NULL;
578 real->table = NULL;
579 real->bucket = NULL;
580 return FALSE;
581 }
582
583 real->bucket = &(real->table->buckets[real->next_bucket]);
584 real->next_entry = *(real->bucket);
585 real->next_bucket += 1;
586 }
587
588 _dbus_assert (real->next_entry != NULL);
589 _dbus_assert (real->bucket != NULL);
590
591 real->entry = real->next_entry;
592 real->next_entry = real->entry->next;
593
594 return TRUE;
595 }
596
597 /**
598 * Removes the current entry from the hash table.
599 * If a key_free_function or value_free_function
600 * was provided to _dbus_hash_table_new(),
601 * frees the key and/or value for this entry.
602 *
603 * @param iter the hash table iterator.
604 */
605 void
_dbus_hash_iter_remove_entry(DBusHashIter * iter)606 _dbus_hash_iter_remove_entry (DBusHashIter *iter)
607 {
608 DBusRealHashIter *real;
609
610 real = (DBusRealHashIter*) iter;
611
612 _dbus_assert (real->table != NULL);
613 _dbus_assert (real->entry != NULL);
614 _dbus_assert (real->bucket != NULL);
615
616 remove_entry (real->table, real->bucket, real->entry);
617
618 real->entry = NULL; /* make it crash if you try to use this entry */
619 }
620
621 /**
622 * Gets the value of the current entry.
623 *
624 * @param iter the hash table iterator.
625 */
626 void*
_dbus_hash_iter_get_value(DBusHashIter * iter)627 _dbus_hash_iter_get_value (DBusHashIter *iter)
628 {
629 DBusRealHashIter *real;
630
631 real = (DBusRealHashIter*) iter;
632
633 _dbus_assert (real->table != NULL);
634 _dbus_assert (real->entry != NULL);
635
636 return real->entry->value;
637 }
638
639 /**
640 * Sets the value of the current entry.
641 * If the hash table has a value_free_function
642 * it will be used to free the previous value.
643 * The hash table will own the passed-in value
644 * (it will not be copied).
645 *
646 * @param iter the hash table iterator.
647 * @param value the new value.
648 */
649 void
_dbus_hash_iter_set_value(DBusHashIter * iter,void * value)650 _dbus_hash_iter_set_value (DBusHashIter *iter,
651 void *value)
652 {
653 DBusRealHashIter *real;
654
655 real = (DBusRealHashIter*) iter;
656
657 _dbus_assert (real->table != NULL);
658 _dbus_assert (real->entry != NULL);
659
660 if (real->table->free_value_function && value != real->entry->value)
661 (* real->table->free_value_function) (real->entry->value);
662
663 real->entry->value = value;
664 }
665
666 /**
667 * Gets the key for the current entry.
668 * Only works for hash tables of type #DBUS_HASH_INT.
669 *
670 * @param iter the hash table iterator.
671 */
672 int
_dbus_hash_iter_get_int_key(DBusHashIter * iter)673 _dbus_hash_iter_get_int_key (DBusHashIter *iter)
674 {
675 DBusRealHashIter *real;
676
677 real = (DBusRealHashIter*) iter;
678
679 _dbus_assert (real->table != NULL);
680 _dbus_assert (real->entry != NULL);
681
682 return _DBUS_POINTER_TO_INT (real->entry->key);
683 }
684
685 /**
686 * Gets the key for the current entry.
687 * Only works for hash tables of type #DBUS_HASH_UINTPTR.
688 *
689 * @param iter the hash table iterator.
690 */
691 uintptr_t
_dbus_hash_iter_get_uintptr_key(DBusHashIter * iter)692 _dbus_hash_iter_get_uintptr_key (DBusHashIter *iter)
693 {
694 DBusRealHashIter *real;
695
696 real = (DBusRealHashIter*) iter;
697
698 _dbus_assert (real->table != NULL);
699 _dbus_assert (real->entry != NULL);
700
701 return (uintptr_t) real->entry->key;
702 }
703
704 /**
705 * Gets the key for the current entry.
706 * Only works for hash tables of type #DBUS_HASH_STRING
707 * @param iter the hash table iterator.
708 */
709 const char*
_dbus_hash_iter_get_string_key(DBusHashIter * iter)710 _dbus_hash_iter_get_string_key (DBusHashIter *iter)
711 {
712 DBusRealHashIter *real;
713
714 real = (DBusRealHashIter*) iter;
715
716 _dbus_assert (real->table != NULL);
717 _dbus_assert (real->entry != NULL);
718
719 return real->entry->key;
720 }
721
722 #ifdef DBUS_BUILD_TESTS
723 /**
724 * Gets the key for the current entry.
725 * Only works for hash tables of type #DBUS_HASH_TWO_STRINGS
726 * @param iter the hash table iterator.
727 */
728 const char*
_dbus_hash_iter_get_two_strings_key(DBusHashIter * iter)729 _dbus_hash_iter_get_two_strings_key (DBusHashIter *iter)
730 {
731 DBusRealHashIter *real;
732
733 real = (DBusRealHashIter*) iter;
734
735 _dbus_assert (real->table != NULL);
736 _dbus_assert (real->entry != NULL);
737
738 return real->entry->key;
739 }
740 #endif /* DBUS_BUILD_TESTS */
741
742 /**
743 * A low-level but efficient interface for manipulating the hash
744 * table. It's efficient because you can get, set, and optionally
745 * create the hash entry while only running the hash function one
746 * time.
747 *
748 * Note that while calling _dbus_hash_iter_next() on the iterator
749 * filled in by this function may work, it's completely
750 * undefined which entries are after this iter and which
751 * are before it. So it would be silly to iterate using this
752 * iterator.
753 *
754 * If the hash entry is created, its value will be initialized
755 * to all bits zero.
756 *
757 * #FALSE may be returned due to memory allocation failure, or
758 * because create_if_not_found was #FALSE and the entry
759 * did not exist.
760 *
761 * If create_if_not_found is #TRUE and the entry is created, the hash
762 * table takes ownership of the key that's passed in.
763 *
764 * For a hash table of type #DBUS_HASH_INT, cast the int
765 * key to the key parameter using #_DBUS_INT_TO_POINTER().
766 *
767 * @param table the hash table.
768 * @param key the hash key.
769 * @param create_if_not_found if #TRUE, create the entry if it didn't exist.
770 * @param iter the iterator to initialize.
771 * @returns #TRUE if the hash entry now exists (and the iterator is thus valid).
772 */
773 dbus_bool_t
_dbus_hash_iter_lookup(DBusHashTable * table,void * key,dbus_bool_t create_if_not_found,DBusHashIter * iter)774 _dbus_hash_iter_lookup (DBusHashTable *table,
775 void *key,
776 dbus_bool_t create_if_not_found,
777 DBusHashIter *iter)
778 {
779 DBusRealHashIter *real;
780 DBusHashEntry *entry;
781 DBusHashEntry **bucket;
782
783 _dbus_assert (sizeof (DBusHashIter) == sizeof (DBusRealHashIter));
784
785 real = (DBusRealHashIter*) iter;
786
787 entry = (* table->find_function) (table, key, create_if_not_found, &bucket, NULL);
788
789 if (entry == NULL)
790 return FALSE;
791
792 real->table = table;
793 real->bucket = bucket;
794 real->entry = entry;
795 real->next_entry = entry->next;
796 real->next_bucket = (bucket - table->buckets) + 1;
797 real->n_entries_on_init = table->n_entries;
798
799 _dbus_assert (&(table->buckets[real->next_bucket-1]) == real->bucket);
800
801 return TRUE;
802 }
803
804 static void
add_allocated_entry(DBusHashTable * table,DBusHashEntry * entry,unsigned int idx,void * key,DBusHashEntry *** bucket)805 add_allocated_entry (DBusHashTable *table,
806 DBusHashEntry *entry,
807 unsigned int idx,
808 void *key,
809 DBusHashEntry ***bucket)
810 {
811 DBusHashEntry **b;
812
813 entry->key = key;
814
815 b = &(table->buckets[idx]);
816 entry->next = *b;
817 *b = entry;
818
819 if (bucket)
820 *bucket = b;
821
822 table->n_entries += 1;
823
824 /* note we ONLY rebuild when ADDING - because you can iterate over a
825 * table and remove entries safely.
826 */
827 if (table->n_entries >= table->hi_rebuild_size ||
828 table->n_entries < table->lo_rebuild_size)
829 rebuild_table (table);
830 }
831
832 static DBusHashEntry*
add_entry(DBusHashTable * table,unsigned int idx,void * key,DBusHashEntry *** bucket,DBusPreallocatedHash * preallocated)833 add_entry (DBusHashTable *table,
834 unsigned int idx,
835 void *key,
836 DBusHashEntry ***bucket,
837 DBusPreallocatedHash *preallocated)
838 {
839 DBusHashEntry *entry;
840
841 if (preallocated == NULL)
842 {
843 entry = alloc_entry (table);
844 if (entry == NULL)
845 {
846 if (bucket)
847 *bucket = NULL;
848 return NULL;
849 }
850 }
851 else
852 {
853 entry = (DBusHashEntry*) preallocated;
854 }
855
856 add_allocated_entry (table, entry, idx, key, bucket);
857
858 return entry;
859 }
860
861 /* This is g_str_hash from GLib which was
862 * extensively discussed/tested/profiled
863 */
864 static unsigned int
string_hash(const char * str)865 string_hash (const char *str)
866 {
867 const char *p = str;
868 unsigned int h = *p;
869
870 if (h)
871 for (p += 1; *p != '\0'; p++)
872 h = (h << 5) - h + *p;
873
874 return h;
875 }
876
877 #ifdef DBUS_BUILD_TESTS
878 /* This hashes a memory block with two nul-terminated strings
879 * in it, used in dbus-object-registry.c at the moment.
880 */
881 static unsigned int
two_strings_hash(const char * str)882 two_strings_hash (const char *str)
883 {
884 const char *p = str;
885 unsigned int h = *p;
886
887 if (h)
888 for (p += 1; *p != '\0'; p++)
889 h = (h << 5) - h + *p;
890
891 for (p += 1; *p != '\0'; p++)
892 h = (h << 5) - h + *p;
893
894 return h;
895 }
896 #endif /* DBUS_BUILD_TESTS */
897
898 /** Key comparison function */
899 typedef int (* KeyCompareFunc) (const void *key_a, const void *key_b);
900
901 static DBusHashEntry*
find_generic_function(DBusHashTable * table,void * key,unsigned int idx,KeyCompareFunc compare_func,dbus_bool_t create_if_not_found,DBusHashEntry *** bucket,DBusPreallocatedHash * preallocated)902 find_generic_function (DBusHashTable *table,
903 void *key,
904 unsigned int idx,
905 KeyCompareFunc compare_func,
906 dbus_bool_t create_if_not_found,
907 DBusHashEntry ***bucket,
908 DBusPreallocatedHash *preallocated)
909 {
910 DBusHashEntry *entry;
911
912 if (bucket)
913 *bucket = NULL;
914
915 /* Search all of the entries in this bucket. */
916 entry = table->buckets[idx];
917 while (entry != NULL)
918 {
919 if ((compare_func == NULL && key == entry->key) ||
920 (compare_func != NULL && (* compare_func) (key, entry->key) == 0))
921 {
922 if (bucket)
923 *bucket = &(table->buckets[idx]);
924
925 if (preallocated)
926 _dbus_hash_table_free_preallocated_entry (table, preallocated);
927
928 return entry;
929 }
930
931 entry = entry->next;
932 }
933
934 if (create_if_not_found)
935 entry = add_entry (table, idx, key, bucket, preallocated);
936 else if (preallocated)
937 _dbus_hash_table_free_preallocated_entry (table, preallocated);
938
939 return entry;
940 }
941
942 static DBusHashEntry*
find_string_function(DBusHashTable * table,void * key,dbus_bool_t create_if_not_found,DBusHashEntry *** bucket,DBusPreallocatedHash * preallocated)943 find_string_function (DBusHashTable *table,
944 void *key,
945 dbus_bool_t create_if_not_found,
946 DBusHashEntry ***bucket,
947 DBusPreallocatedHash *preallocated)
948 {
949 unsigned int idx;
950
951 idx = string_hash (key) & table->mask;
952
953 return find_generic_function (table, key, idx,
954 (KeyCompareFunc) strcmp, create_if_not_found, bucket,
955 preallocated);
956 }
957
958 #ifdef DBUS_BUILD_TESTS
959 static int
two_strings_cmp(const char * a,const char * b)960 two_strings_cmp (const char *a,
961 const char *b)
962 {
963 size_t len_a;
964 size_t len_b;
965 int res;
966
967 res = strcmp (a, b);
968 if (res != 0)
969 return res;
970
971 len_a = strlen (a);
972 len_b = strlen (b);
973
974 return strcmp (a + len_a + 1, b + len_b + 1);
975 }
976 #endif
977
978 #ifdef DBUS_BUILD_TESTS
979 static DBusHashEntry*
find_two_strings_function(DBusHashTable * table,void * key,dbus_bool_t create_if_not_found,DBusHashEntry *** bucket,DBusPreallocatedHash * preallocated)980 find_two_strings_function (DBusHashTable *table,
981 void *key,
982 dbus_bool_t create_if_not_found,
983 DBusHashEntry ***bucket,
984 DBusPreallocatedHash *preallocated)
985 {
986 unsigned int idx;
987
988 idx = two_strings_hash (key) & table->mask;
989
990 return find_generic_function (table, key, idx,
991 (KeyCompareFunc) two_strings_cmp, create_if_not_found, bucket,
992 preallocated);
993 }
994 #endif /* DBUS_BUILD_TESTS */
995
996 static DBusHashEntry*
find_direct_function(DBusHashTable * table,void * key,dbus_bool_t create_if_not_found,DBusHashEntry *** bucket,DBusPreallocatedHash * preallocated)997 find_direct_function (DBusHashTable *table,
998 void *key,
999 dbus_bool_t create_if_not_found,
1000 DBusHashEntry ***bucket,
1001 DBusPreallocatedHash *preallocated)
1002 {
1003 unsigned int idx;
1004
1005 idx = RANDOM_INDEX (table, key) & table->mask;
1006
1007
1008 return find_generic_function (table, key, idx,
1009 NULL, create_if_not_found, bucket,
1010 preallocated);
1011 }
1012
1013 static void
rebuild_table(DBusHashTable * table)1014 rebuild_table (DBusHashTable *table)
1015 {
1016 int old_size;
1017 int new_buckets;
1018 DBusHashEntry **old_buckets;
1019 DBusHashEntry **old_chain;
1020 DBusHashEntry *entry;
1021 dbus_bool_t growing;
1022
1023 /*
1024 * Allocate and initialize the new bucket array, and set up
1025 * hashing constants for new array size.
1026 */
1027
1028 growing = table->n_entries >= table->hi_rebuild_size;
1029
1030 old_size = table->n_buckets;
1031 old_buckets = table->buckets;
1032
1033 if (growing)
1034 {
1035 /* overflow paranoia */
1036 if (table->n_buckets < _DBUS_INT_MAX / 4 &&
1037 table->down_shift >= 0)
1038 new_buckets = table->n_buckets * 4;
1039 else
1040 return; /* can't grow anymore */
1041 }
1042 else
1043 {
1044 new_buckets = table->n_buckets / 4;
1045 if (new_buckets < DBUS_SMALL_HASH_TABLE)
1046 return; /* don't bother shrinking this far */
1047 }
1048
1049 table->buckets = dbus_new0 (DBusHashEntry*, new_buckets);
1050 if (table->buckets == NULL)
1051 {
1052 /* out of memory, yay - just don't reallocate, the table will
1053 * still work, albeit more slowly.
1054 */
1055 table->buckets = old_buckets;
1056 return;
1057 }
1058
1059 table->n_buckets = new_buckets;
1060
1061 if (growing)
1062 {
1063 table->lo_rebuild_size = table->hi_rebuild_size;
1064 table->hi_rebuild_size *= 4;
1065
1066 table->down_shift -= 2; /* keep 2 more high bits */
1067 table->mask = (table->mask << 2) + 3; /* keep 2 more high bits */
1068 }
1069 else
1070 {
1071 table->hi_rebuild_size = table->lo_rebuild_size;
1072 table->lo_rebuild_size /= 4;
1073
1074 table->down_shift += 2; /* keep 2 fewer high bits */
1075 table->mask = table->mask >> 2; /* keep 2 fewer high bits */
1076 }
1077
1078 #if 0
1079 printf ("%s table to lo = %d hi = %d downshift = %d mask = 0x%x\n",
1080 growing ? "GROW" : "SHRINK",
1081 table->lo_rebuild_size,
1082 table->hi_rebuild_size,
1083 table->down_shift,
1084 table->mask);
1085 #endif
1086
1087 _dbus_assert (table->lo_rebuild_size >= 0);
1088 _dbus_assert (table->hi_rebuild_size > table->lo_rebuild_size);
1089 _dbus_assert (table->mask != 0);
1090 /* the mask is essentially the max index */
1091 _dbus_assert (table->mask < table->n_buckets);
1092
1093 /*
1094 * Rehash all of the existing entries into the new bucket array.
1095 */
1096
1097 for (old_chain = old_buckets; old_size > 0; old_size--, old_chain++)
1098 {
1099 for (entry = *old_chain; entry != NULL; entry = *old_chain)
1100 {
1101 unsigned int idx;
1102 DBusHashEntry **bucket;
1103
1104 *old_chain = entry->next;
1105 switch (table->key_type)
1106 {
1107 case DBUS_HASH_STRING:
1108 idx = string_hash (entry->key) & table->mask;
1109 break;
1110 case DBUS_HASH_TWO_STRINGS:
1111 #ifdef DBUS_BUILD_TESTS
1112 idx = two_strings_hash (entry->key) & table->mask;
1113 #else
1114 idx = 0;
1115 _dbus_assert_not_reached ("two-strings is not enabled");
1116 #endif
1117 break;
1118 case DBUS_HASH_INT:
1119 case DBUS_HASH_UINTPTR:
1120 case DBUS_HASH_POINTER:
1121 idx = RANDOM_INDEX (table, entry->key);
1122 break;
1123 default:
1124 idx = 0;
1125 _dbus_assert_not_reached ("Unknown hash table type");
1126 break;
1127 }
1128
1129 bucket = &(table->buckets[idx]);
1130 entry->next = *bucket;
1131 *bucket = entry;
1132 }
1133 }
1134
1135 /* Free the old bucket array, if it was dynamically allocated. */
1136
1137 if (old_buckets != table->static_buckets)
1138 dbus_free (old_buckets);
1139 }
1140
1141 /**
1142 * Looks up the value for a given string in a hash table
1143 * of type #DBUS_HASH_STRING. Returns %NULL if the value
1144 * is not present. (A not-present entry is indistinguishable
1145 * from an entry with a value of %NULL.)
1146 * @param table the hash table.
1147 * @param key the string to look up.
1148 * @returns the value of the hash entry.
1149 */
1150 void*
_dbus_hash_table_lookup_string(DBusHashTable * table,const char * key)1151 _dbus_hash_table_lookup_string (DBusHashTable *table,
1152 const char *key)
1153 {
1154 DBusHashEntry *entry;
1155
1156 _dbus_assert (table->key_type == DBUS_HASH_STRING);
1157
1158 entry = (* table->find_function) (table, (char*) key, FALSE, NULL, NULL);
1159
1160 if (entry)
1161 return entry->value;
1162 else
1163 return NULL;
1164 }
1165
1166 #ifdef DBUS_BUILD_TESTS
1167 /**
1168 * Looks up the value for a given string in a hash table
1169 * of type #DBUS_HASH_TWO_STRINGS. Returns %NULL if the value
1170 * is not present. (A not-present entry is indistinguishable
1171 * from an entry with a value of %NULL.)
1172 * @param table the hash table.
1173 * @param key the string to look up.
1174 * @returns the value of the hash entry.
1175 */
1176 void*
_dbus_hash_table_lookup_two_strings(DBusHashTable * table,const char * key)1177 _dbus_hash_table_lookup_two_strings (DBusHashTable *table,
1178 const char *key)
1179 {
1180 DBusHashEntry *entry;
1181
1182 _dbus_assert (table->key_type == DBUS_HASH_TWO_STRINGS);
1183
1184 entry = (* table->find_function) (table, (char*) key, FALSE, NULL, NULL);
1185
1186 if (entry)
1187 return entry->value;
1188 else
1189 return NULL;
1190 }
1191 #endif /* DBUS_BUILD_TESTS */
1192
1193 /**
1194 * Looks up the value for a given integer in a hash table
1195 * of type #DBUS_HASH_INT. Returns %NULL if the value
1196 * is not present. (A not-present entry is indistinguishable
1197 * from an entry with a value of %NULL.)
1198 * @param table the hash table.
1199 * @param key the integer to look up.
1200 * @returns the value of the hash entry.
1201 */
1202 void*
_dbus_hash_table_lookup_int(DBusHashTable * table,int key)1203 _dbus_hash_table_lookup_int (DBusHashTable *table,
1204 int key)
1205 {
1206 DBusHashEntry *entry;
1207
1208 _dbus_assert (table->key_type == DBUS_HASH_INT);
1209
1210 entry = (* table->find_function) (table, _DBUS_INT_TO_POINTER (key), FALSE, NULL, NULL);
1211
1212 if (entry)
1213 return entry->value;
1214 else
1215 return NULL;
1216 }
1217
1218 #ifdef DBUS_BUILD_TESTS
1219 /* disabled since it's only used for testing */
1220 /**
1221 * Looks up the value for a given integer in a hash table
1222 * of type #DBUS_HASH_POINTER. Returns %NULL if the value
1223 * is not present. (A not-present entry is indistinguishable
1224 * from an entry with a value of %NULL.)
1225 * @param table the hash table.
1226 * @param key the integer to look up.
1227 * @returns the value of the hash entry.
1228 */
1229 void*
_dbus_hash_table_lookup_pointer(DBusHashTable * table,void * key)1230 _dbus_hash_table_lookup_pointer (DBusHashTable *table,
1231 void *key)
1232 {
1233 DBusHashEntry *entry;
1234
1235 _dbus_assert (table->key_type == DBUS_HASH_POINTER);
1236
1237 entry = (* table->find_function) (table, key, FALSE, NULL, NULL);
1238
1239 if (entry)
1240 return entry->value;
1241 else
1242 return NULL;
1243 }
1244 #endif /* DBUS_BUILD_TESTS */
1245
1246 /**
1247 * Looks up the value for a given integer in a hash table
1248 * of type #DBUS_HASH_UINTPTR. Returns %NULL if the value
1249 * is not present. (A not-present entry is indistinguishable
1250 * from an entry with a value of %NULL.)
1251 * @param table the hash table.
1252 * @param key the integer to look up.
1253 * @returns the value of the hash entry.
1254 */
1255 void*
_dbus_hash_table_lookup_uintptr(DBusHashTable * table,uintptr_t key)1256 _dbus_hash_table_lookup_uintptr (DBusHashTable *table,
1257 uintptr_t key)
1258 {
1259 DBusHashEntry *entry;
1260
1261 _dbus_assert (table->key_type == DBUS_HASH_UINTPTR);
1262
1263 entry = (* table->find_function) (table, (void*) key, FALSE, NULL, NULL);
1264
1265 if (entry)
1266 return entry->value;
1267 else
1268 return NULL;
1269 }
1270
1271 /**
1272 * Removes the hash entry for the given key. If no hash entry
1273 * for the key exists, does nothing.
1274 *
1275 * @param table the hash table.
1276 * @param key the hash key.
1277 * @returns #TRUE if the entry existed
1278 */
1279 dbus_bool_t
_dbus_hash_table_remove_string(DBusHashTable * table,const char * key)1280 _dbus_hash_table_remove_string (DBusHashTable *table,
1281 const char *key)
1282 {
1283 DBusHashEntry *entry;
1284 DBusHashEntry **bucket;
1285
1286 _dbus_assert (table->key_type == DBUS_HASH_STRING);
1287
1288 entry = (* table->find_function) (table, (char*) key, FALSE, &bucket, NULL);
1289
1290 if (entry)
1291 {
1292 remove_entry (table, bucket, entry);
1293 return TRUE;
1294 }
1295 else
1296 return FALSE;
1297 }
1298
1299 #ifdef DBUS_BUILD_TESTS
1300 /**
1301 * Removes the hash entry for the given key. If no hash entry
1302 * for the key exists, does nothing.
1303 *
1304 * @param table the hash table.
1305 * @param key the hash key.
1306 * @returns #TRUE if the entry existed
1307 */
1308 dbus_bool_t
_dbus_hash_table_remove_two_strings(DBusHashTable * table,const char * key)1309 _dbus_hash_table_remove_two_strings (DBusHashTable *table,
1310 const char *key)
1311 {
1312 DBusHashEntry *entry;
1313 DBusHashEntry **bucket;
1314
1315 _dbus_assert (table->key_type == DBUS_HASH_TWO_STRINGS);
1316
1317 entry = (* table->find_function) (table, (char*) key, FALSE, &bucket, NULL);
1318
1319 if (entry)
1320 {
1321 remove_entry (table, bucket, entry);
1322 return TRUE;
1323 }
1324 else
1325 return FALSE;
1326 }
1327 #endif /* DBUS_BUILD_TESTS */
1328
1329 /**
1330 * Removes the hash entry for the given key. If no hash entry
1331 * for the key exists, does nothing.
1332 *
1333 * @param table the hash table.
1334 * @param key the hash key.
1335 * @returns #TRUE if the entry existed
1336 */
1337 dbus_bool_t
_dbus_hash_table_remove_int(DBusHashTable * table,int key)1338 _dbus_hash_table_remove_int (DBusHashTable *table,
1339 int key)
1340 {
1341 DBusHashEntry *entry;
1342 DBusHashEntry **bucket;
1343
1344 _dbus_assert (table->key_type == DBUS_HASH_INT);
1345
1346 entry = (* table->find_function) (table, _DBUS_INT_TO_POINTER (key), FALSE, &bucket, NULL);
1347
1348 if (entry)
1349 {
1350 remove_entry (table, bucket, entry);
1351 return TRUE;
1352 }
1353 else
1354 return FALSE;
1355 }
1356
1357 #ifdef DBUS_BUILD_TESTS
1358 /* disabled since it's only used for testing */
1359 /**
1360 * Removes the hash entry for the given key. If no hash entry
1361 * for the key exists, does nothing.
1362 *
1363 * @param table the hash table.
1364 * @param key the hash key.
1365 * @returns #TRUE if the entry existed
1366 */
1367 dbus_bool_t
_dbus_hash_table_remove_pointer(DBusHashTable * table,void * key)1368 _dbus_hash_table_remove_pointer (DBusHashTable *table,
1369 void *key)
1370 {
1371 DBusHashEntry *entry;
1372 DBusHashEntry **bucket;
1373
1374 _dbus_assert (table->key_type == DBUS_HASH_POINTER);
1375
1376 entry = (* table->find_function) (table, key, FALSE, &bucket, NULL);
1377
1378 if (entry)
1379 {
1380 remove_entry (table, bucket, entry);
1381 return TRUE;
1382 }
1383 else
1384 return FALSE;
1385 }
1386 #endif /* DBUS_BUILD_TESTS */
1387
1388 /**
1389 * Removes the hash entry for the given key. If no hash entry
1390 * for the key exists, does nothing.
1391 *
1392 * @param table the hash table.
1393 * @param key the hash key.
1394 * @returns #TRUE if the entry existed
1395 */
1396 dbus_bool_t
_dbus_hash_table_remove_uintptr(DBusHashTable * table,uintptr_t key)1397 _dbus_hash_table_remove_uintptr (DBusHashTable *table,
1398 uintptr_t key)
1399 {
1400 DBusHashEntry *entry;
1401 DBusHashEntry **bucket;
1402
1403 _dbus_assert (table->key_type == DBUS_HASH_UINTPTR);
1404
1405 entry = (* table->find_function) (table, (void*) key, FALSE, &bucket, NULL);
1406
1407 if (entry)
1408 {
1409 remove_entry (table, bucket, entry);
1410 return TRUE;
1411 }
1412 else
1413 return FALSE;
1414 }
1415
1416 /**
1417 * Creates a hash entry with the given key and value.
1418 * The key and value are not copied; they are stored
1419 * in the hash table by reference. If an entry with the
1420 * given key already exists, the previous key and value
1421 * are overwritten (and freed if the hash table has
1422 * a key_free_function and/or value_free_function).
1423 *
1424 * Returns #FALSE if memory for the new hash entry
1425 * can't be allocated.
1426 *
1427 * @param table the hash table.
1428 * @param key the hash entry key.
1429 * @param value the hash entry value.
1430 */
1431 dbus_bool_t
_dbus_hash_table_insert_string(DBusHashTable * table,char * key,void * value)1432 _dbus_hash_table_insert_string (DBusHashTable *table,
1433 char *key,
1434 void *value)
1435 {
1436 DBusPreallocatedHash *preallocated;
1437
1438 _dbus_assert (table->key_type == DBUS_HASH_STRING);
1439
1440 preallocated = _dbus_hash_table_preallocate_entry (table);
1441 if (preallocated == NULL)
1442 return FALSE;
1443
1444 _dbus_hash_table_insert_string_preallocated (table, preallocated,
1445 key, value);
1446
1447 return TRUE;
1448 }
1449
1450 #ifdef DBUS_BUILD_TESTS
1451 /**
1452 * Creates a hash entry with the given key and value.
1453 * The key and value are not copied; they are stored
1454 * in the hash table by reference. If an entry with the
1455 * given key already exists, the previous key and value
1456 * are overwritten (and freed if the hash table has
1457 * a key_free_function and/or value_free_function).
1458 *
1459 * Returns #FALSE if memory for the new hash entry
1460 * can't be allocated.
1461 *
1462 * @param table the hash table.
1463 * @param key the hash entry key.
1464 * @param value the hash entry value.
1465 */
1466 dbus_bool_t
_dbus_hash_table_insert_two_strings(DBusHashTable * table,char * key,void * value)1467 _dbus_hash_table_insert_two_strings (DBusHashTable *table,
1468 char *key,
1469 void *value)
1470 {
1471 DBusHashEntry *entry;
1472
1473 _dbus_assert (table->key_type == DBUS_HASH_TWO_STRINGS);
1474
1475 entry = (* table->find_function) (table, key, TRUE, NULL, NULL);
1476
1477 if (entry == NULL)
1478 return FALSE; /* no memory */
1479
1480 if (table->free_key_function && entry->key != key)
1481 (* table->free_key_function) (entry->key);
1482
1483 if (table->free_value_function && entry->value != value)
1484 (* table->free_value_function) (entry->value);
1485
1486 entry->key = key;
1487 entry->value = value;
1488
1489 return TRUE;
1490 }
1491 #endif /* DBUS_BUILD_TESTS */
1492
1493 /**
1494 * Creates a hash entry with the given key and value.
1495 * The key and value are not copied; they are stored
1496 * in the hash table by reference. If an entry with the
1497 * given key already exists, the previous key and value
1498 * are overwritten (and freed if the hash table has
1499 * a key_free_function and/or value_free_function).
1500 *
1501 * Returns #FALSE if memory for the new hash entry
1502 * can't be allocated.
1503 *
1504 * @param table the hash table.
1505 * @param key the hash entry key.
1506 * @param value the hash entry value.
1507 */
1508 dbus_bool_t
_dbus_hash_table_insert_int(DBusHashTable * table,int key,void * value)1509 _dbus_hash_table_insert_int (DBusHashTable *table,
1510 int key,
1511 void *value)
1512 {
1513 DBusHashEntry *entry;
1514
1515 _dbus_assert (table->key_type == DBUS_HASH_INT);
1516
1517 entry = (* table->find_function) (table, _DBUS_INT_TO_POINTER (key), TRUE, NULL, NULL);
1518
1519 if (entry == NULL)
1520 return FALSE; /* no memory */
1521
1522 if (table->free_key_function && entry->key != _DBUS_INT_TO_POINTER (key))
1523 (* table->free_key_function) (entry->key);
1524
1525 if (table->free_value_function && entry->value != value)
1526 (* table->free_value_function) (entry->value);
1527
1528 entry->key = _DBUS_INT_TO_POINTER (key);
1529 entry->value = value;
1530
1531 return TRUE;
1532 }
1533
1534 #ifdef DBUS_BUILD_TESTS
1535 /* disabled since it's only used for testing */
1536 /**
1537 * Creates a hash entry with the given key and value.
1538 * The key and value are not copied; they are stored
1539 * in the hash table by reference. If an entry with the
1540 * given key already exists, the previous key and value
1541 * are overwritten (and freed if the hash table has
1542 * a key_free_function and/or value_free_function).
1543 *
1544 * Returns #FALSE if memory for the new hash entry
1545 * can't be allocated.
1546 *
1547 * @param table the hash table.
1548 * @param key the hash entry key.
1549 * @param value the hash entry value.
1550 */
1551 dbus_bool_t
_dbus_hash_table_insert_pointer(DBusHashTable * table,void * key,void * value)1552 _dbus_hash_table_insert_pointer (DBusHashTable *table,
1553 void *key,
1554 void *value)
1555 {
1556 DBusHashEntry *entry;
1557
1558 _dbus_assert (table->key_type == DBUS_HASH_POINTER);
1559
1560 entry = (* table->find_function) (table, key, TRUE, NULL, NULL);
1561
1562 if (entry == NULL)
1563 return FALSE; /* no memory */
1564
1565 if (table->free_key_function && entry->key != key)
1566 (* table->free_key_function) (entry->key);
1567
1568 if (table->free_value_function && entry->value != value)
1569 (* table->free_value_function) (entry->value);
1570
1571 entry->key = key;
1572 entry->value = value;
1573
1574 return TRUE;
1575 }
1576 #endif /* DBUS_BUILD_TESTS */
1577
1578 /**
1579 * Creates a hash entry with the given key and value.
1580 * The key and value are not copied; they are stored
1581 * in the hash table by reference. If an entry with the
1582 * given key already exists, the previous key and value
1583 * are overwritten (and freed if the hash table has
1584 * a key_free_function and/or value_free_function).
1585 *
1586 * Returns #FALSE if memory for the new hash entry
1587 * can't be allocated.
1588 *
1589 * @param table the hash table.
1590 * @param key the hash entry key.
1591 * @param value the hash entry value.
1592 */
1593 dbus_bool_t
_dbus_hash_table_insert_uintptr(DBusHashTable * table,uintptr_t key,void * value)1594 _dbus_hash_table_insert_uintptr (DBusHashTable *table,
1595 uintptr_t key,
1596 void *value)
1597 {
1598 DBusHashEntry *entry;
1599
1600 _dbus_assert (table->key_type == DBUS_HASH_UINTPTR);
1601
1602 entry = (* table->find_function) (table, (void*) key, TRUE, NULL, NULL);
1603
1604 if (entry == NULL)
1605 return FALSE; /* no memory */
1606
1607 if (table->free_key_function && entry->key != (void*) key)
1608 (* table->free_key_function) (entry->key);
1609
1610 if (table->free_value_function && entry->value != value)
1611 (* table->free_value_function) (entry->value);
1612
1613 entry->key = (void*) key;
1614 entry->value = value;
1615
1616 return TRUE;
1617 }
1618
1619 /**
1620 * Preallocate an opaque data blob that allows us to insert into the
1621 * hash table at a later time without allocating any memory.
1622 *
1623 * @param table the hash table
1624 * @returns the preallocated data, or #NULL if no memory
1625 */
1626 DBusPreallocatedHash*
_dbus_hash_table_preallocate_entry(DBusHashTable * table)1627 _dbus_hash_table_preallocate_entry (DBusHashTable *table)
1628 {
1629 DBusHashEntry *entry;
1630
1631 entry = alloc_entry (table);
1632
1633 return (DBusPreallocatedHash*) entry;
1634 }
1635
1636 /**
1637 * Frees an opaque DBusPreallocatedHash that was *not* used
1638 * in order to insert into the hash table.
1639 *
1640 * @param table the hash table
1641 * @param preallocated the preallocated data
1642 */
1643 void
_dbus_hash_table_free_preallocated_entry(DBusHashTable * table,DBusPreallocatedHash * preallocated)1644 _dbus_hash_table_free_preallocated_entry (DBusHashTable *table,
1645 DBusPreallocatedHash *preallocated)
1646 {
1647 DBusHashEntry *entry;
1648
1649 _dbus_assert (preallocated != NULL);
1650
1651 entry = (DBusHashEntry*) preallocated;
1652
1653 /* Don't use free_entry(), since this entry has no key/data */
1654 _dbus_mem_pool_dealloc (table->entry_pool, entry);
1655 }
1656
1657 /**
1658 * Inserts a string-keyed entry into the hash table, using a
1659 * preallocated data block from
1660 * _dbus_hash_table_preallocate_entry(). This function cannot fail due
1661 * to lack of memory. The DBusPreallocatedHash object is consumed and
1662 * should not be reused or freed. Otherwise this function works
1663 * just like _dbus_hash_table_insert_string().
1664 *
1665 * @param table the hash table
1666 * @param preallocated the preallocated data
1667 * @param key the hash key
1668 * @param value the value
1669 */
1670 void
_dbus_hash_table_insert_string_preallocated(DBusHashTable * table,DBusPreallocatedHash * preallocated,char * key,void * value)1671 _dbus_hash_table_insert_string_preallocated (DBusHashTable *table,
1672 DBusPreallocatedHash *preallocated,
1673 char *key,
1674 void *value)
1675 {
1676 DBusHashEntry *entry;
1677
1678 _dbus_assert (table->key_type == DBUS_HASH_STRING);
1679 _dbus_assert (preallocated != NULL);
1680
1681 entry = (* table->find_function) (table, key, TRUE, NULL, preallocated);
1682
1683 _dbus_assert (entry != NULL);
1684
1685 if (table->free_key_function && entry->key != key)
1686 (* table->free_key_function) (entry->key);
1687
1688 if (table->free_value_function && entry->value != value)
1689 (* table->free_value_function) (entry->value);
1690
1691 entry->key = key;
1692 entry->value = value;
1693 }
1694
1695 /**
1696 * Gets the number of hash entries in a hash table.
1697 *
1698 * @param table the hash table.
1699 * @returns the number of entries in the table.
1700 */
1701 int
_dbus_hash_table_get_n_entries(DBusHashTable * table)1702 _dbus_hash_table_get_n_entries (DBusHashTable *table)
1703 {
1704 return table->n_entries;
1705 }
1706
1707 /** @} */
1708
1709 #ifdef DBUS_BUILD_TESTS
1710 #include "dbus-test.h"
1711 #include <stdio.h>
1712
1713 /* If you're wondering why the hash table test takes
1714 * forever to run, it's because we call this function
1715 * in inner loops thus making things quadratic.
1716 */
1717 static int
count_entries(DBusHashTable * table)1718 count_entries (DBusHashTable *table)
1719 {
1720 DBusHashIter iter;
1721 int count;
1722
1723 count = 0;
1724 _dbus_hash_iter_init (table, &iter);
1725 while (_dbus_hash_iter_next (&iter))
1726 ++count;
1727
1728 _dbus_assert (count == _dbus_hash_table_get_n_entries (table));
1729
1730 return count;
1731 }
1732
1733 /* Copy the foo\0bar\0 double string thing */
1734 static char*
_dbus_strdup2(const char * str)1735 _dbus_strdup2 (const char *str)
1736 {
1737 size_t len;
1738 char *copy;
1739
1740 if (str == NULL)
1741 return NULL;
1742
1743 len = strlen (str);
1744 len += strlen ((str + len + 1));
1745
1746 copy = dbus_malloc (len + 2);
1747 if (copy == NULL)
1748 return NULL;
1749
1750 memcpy (copy, str, len + 2);
1751
1752 return copy;
1753 }
1754
1755 /**
1756 * @ingroup DBusHashTableInternals
1757 * Unit test for DBusHashTable
1758 * @returns #TRUE on success.
1759 */
1760 dbus_bool_t
_dbus_hash_test(void)1761 _dbus_hash_test (void)
1762 {
1763 int i;
1764 DBusHashTable *table1;
1765 DBusHashTable *table2;
1766 DBusHashTable *table3;
1767 DBusHashTable *table4;
1768 DBusHashIter iter;
1769 #define N_HASH_KEYS 5000
1770 char **keys;
1771 dbus_bool_t ret = FALSE;
1772
1773 keys = dbus_new (char *, N_HASH_KEYS);
1774 if (keys == NULL)
1775 _dbus_assert_not_reached ("no memory");
1776
1777 for (i = 0; i < N_HASH_KEYS; i++)
1778 {
1779 keys[i] = dbus_malloc (128);
1780
1781 if (keys[i] == NULL)
1782 _dbus_assert_not_reached ("no memory");
1783 }
1784
1785 printf ("Computing test hash keys...\n");
1786 i = 0;
1787 while (i < N_HASH_KEYS)
1788 {
1789 int len;
1790
1791 /* all the hash keys are TWO_STRINGS, but
1792 * then we can also use those as regular strings.
1793 */
1794
1795 len = sprintf (keys[i], "Hash key %d", i);
1796 sprintf (keys[i] + len + 1, "Two string %d", i);
1797 _dbus_assert (*(keys[i] + len) == '\0');
1798 _dbus_assert (*(keys[i] + len + 1) != '\0');
1799 ++i;
1800 }
1801 printf ("... done.\n");
1802
1803 table1 = _dbus_hash_table_new (DBUS_HASH_STRING,
1804 dbus_free, dbus_free);
1805 if (table1 == NULL)
1806 goto out;
1807
1808 table2 = _dbus_hash_table_new (DBUS_HASH_INT,
1809 NULL, dbus_free);
1810 if (table2 == NULL)
1811 goto out;
1812
1813 table3 = _dbus_hash_table_new (DBUS_HASH_UINTPTR,
1814 NULL, dbus_free);
1815 if (table3 == NULL)
1816 goto out;
1817
1818 table4 = _dbus_hash_table_new (DBUS_HASH_TWO_STRINGS,
1819 dbus_free, dbus_free);
1820 if (table4 == NULL)
1821 goto out;
1822
1823
1824 /* Insert and remove a bunch of stuff, counting the table in between
1825 * to be sure it's not broken and that iteration works
1826 */
1827 i = 0;
1828 while (i < 3000)
1829 {
1830 void *value;
1831 char *key;
1832
1833 key = _dbus_strdup (keys[i]);
1834 if (key == NULL)
1835 goto out;
1836 value = _dbus_strdup ("Value!");
1837 if (value == NULL)
1838 goto out;
1839
1840 if (!_dbus_hash_table_insert_string (table1,
1841 key, value))
1842 goto out;
1843
1844 value = _dbus_strdup (keys[i]);
1845 if (value == NULL)
1846 goto out;
1847
1848 if (!_dbus_hash_table_insert_int (table2,
1849 i, value))
1850 goto out;
1851
1852 value = _dbus_strdup (keys[i]);
1853 if (value == NULL)
1854 goto out;
1855
1856 if (!_dbus_hash_table_insert_uintptr (table3,
1857 i, value))
1858 goto out;
1859
1860 key = _dbus_strdup2 (keys[i]);
1861 if (key == NULL)
1862 goto out;
1863 value = _dbus_strdup ("Value!");
1864 if (value == NULL)
1865 goto out;
1866
1867 if (!_dbus_hash_table_insert_two_strings (table4,
1868 key, value))
1869 goto out;
1870
1871 _dbus_assert (count_entries (table1) == i + 1);
1872 _dbus_assert (count_entries (table2) == i + 1);
1873 _dbus_assert (count_entries (table3) == i + 1);
1874 _dbus_assert (count_entries (table4) == i + 1);
1875
1876 value = _dbus_hash_table_lookup_string (table1, keys[i]);
1877 _dbus_assert (value != NULL);
1878 _dbus_assert (strcmp (value, "Value!") == 0);
1879
1880 value = _dbus_hash_table_lookup_int (table2, i);
1881 _dbus_assert (value != NULL);
1882 _dbus_assert (strcmp (value, keys[i]) == 0);
1883
1884 value = _dbus_hash_table_lookup_uintptr (table3, i);
1885 _dbus_assert (value != NULL);
1886 _dbus_assert (strcmp (value, keys[i]) == 0);
1887
1888 value = _dbus_hash_table_lookup_two_strings (table4, keys[i]);
1889 _dbus_assert (value != NULL);
1890 _dbus_assert (strcmp (value, "Value!") == 0);
1891
1892 ++i;
1893 }
1894
1895 --i;
1896 while (i >= 0)
1897 {
1898 _dbus_hash_table_remove_string (table1,
1899 keys[i]);
1900
1901 _dbus_hash_table_remove_int (table2, i);
1902
1903 _dbus_hash_table_remove_uintptr (table3, i);
1904
1905 _dbus_hash_table_remove_two_strings (table4,
1906 keys[i]);
1907
1908 _dbus_assert (count_entries (table1) == i);
1909 _dbus_assert (count_entries (table2) == i);
1910 _dbus_assert (count_entries (table3) == i);
1911 _dbus_assert (count_entries (table4) == i);
1912
1913 --i;
1914 }
1915
1916 _dbus_hash_table_ref (table1);
1917 _dbus_hash_table_ref (table2);
1918 _dbus_hash_table_ref (table3);
1919 _dbus_hash_table_ref (table4);
1920 _dbus_hash_table_unref (table1);
1921 _dbus_hash_table_unref (table2);
1922 _dbus_hash_table_unref (table3);
1923 _dbus_hash_table_unref (table4);
1924 _dbus_hash_table_unref (table1);
1925 _dbus_hash_table_unref (table2);
1926 _dbus_hash_table_unref (table3);
1927 _dbus_hash_table_unref (table4);
1928 table3 = NULL;
1929
1930 /* Insert a bunch of stuff then check
1931 * that iteration works correctly (finds the right
1932 * values, iter_set_value works, etc.)
1933 */
1934 table1 = _dbus_hash_table_new (DBUS_HASH_STRING,
1935 dbus_free, dbus_free);
1936 if (table1 == NULL)
1937 goto out;
1938
1939 table2 = _dbus_hash_table_new (DBUS_HASH_INT,
1940 NULL, dbus_free);
1941 if (table2 == NULL)
1942 goto out;
1943
1944 i = 0;
1945 while (i < 5000)
1946 {
1947 char *key;
1948 void *value;
1949
1950 key = _dbus_strdup (keys[i]);
1951 if (key == NULL)
1952 goto out;
1953 value = _dbus_strdup ("Value!");
1954 if (value == NULL)
1955 goto out;
1956
1957 if (!_dbus_hash_table_insert_string (table1,
1958 key, value))
1959 goto out;
1960
1961 value = _dbus_strdup (keys[i]);
1962 if (value == NULL)
1963 goto out;
1964
1965 if (!_dbus_hash_table_insert_int (table2,
1966 i, value))
1967 goto out;
1968
1969 _dbus_assert (count_entries (table1) == i + 1);
1970 _dbus_assert (count_entries (table2) == i + 1);
1971
1972 ++i;
1973 }
1974
1975 _dbus_hash_iter_init (table1, &iter);
1976 while (_dbus_hash_iter_next (&iter))
1977 {
1978 const char *key;
1979 void *value;
1980
1981 key = _dbus_hash_iter_get_string_key (&iter);
1982 value = _dbus_hash_iter_get_value (&iter);
1983
1984 _dbus_assert (_dbus_hash_table_lookup_string (table1, key) == value);
1985
1986 value = _dbus_strdup ("Different value!");
1987 if (value == NULL)
1988 goto out;
1989
1990 _dbus_hash_iter_set_value (&iter, value);
1991
1992 _dbus_assert (_dbus_hash_table_lookup_string (table1, key) == value);
1993 }
1994
1995 _dbus_hash_iter_init (table1, &iter);
1996 while (_dbus_hash_iter_next (&iter))
1997 {
1998 _dbus_hash_iter_remove_entry (&iter);
1999 _dbus_assert (count_entries (table1) == i - 1);
2000 --i;
2001 }
2002
2003 _dbus_hash_iter_init (table2, &iter);
2004 while (_dbus_hash_iter_next (&iter))
2005 {
2006 int key;
2007 void *value;
2008
2009 key = _dbus_hash_iter_get_int_key (&iter);
2010 value = _dbus_hash_iter_get_value (&iter);
2011
2012 _dbus_assert (_dbus_hash_table_lookup_int (table2, key) == value);
2013
2014 value = _dbus_strdup ("Different value!");
2015 if (value == NULL)
2016 goto out;
2017
2018 _dbus_hash_iter_set_value (&iter, value);
2019
2020 _dbus_assert (_dbus_hash_table_lookup_int (table2, key) == value);
2021 }
2022
2023 i = count_entries (table2);
2024 _dbus_hash_iter_init (table2, &iter);
2025 while (_dbus_hash_iter_next (&iter))
2026 {
2027 _dbus_hash_iter_remove_entry (&iter);
2028 _dbus_assert (count_entries (table2) + 1 == i);
2029 --i;
2030 }
2031
2032 /* add/remove interleaved, to check that we grow/shrink the table
2033 * appropriately
2034 */
2035 i = 0;
2036 while (i < 1000)
2037 {
2038 char *key;
2039 void *value;
2040
2041 key = _dbus_strdup (keys[i]);
2042 if (key == NULL)
2043 goto out;
2044
2045 value = _dbus_strdup ("Value!");
2046 if (value == NULL)
2047 goto out;
2048
2049 if (!_dbus_hash_table_insert_string (table1,
2050 key, value))
2051 goto out;
2052
2053 ++i;
2054 }
2055
2056 --i;
2057 while (i >= 0)
2058 {
2059 char *key;
2060 void *value;
2061
2062 key = _dbus_strdup (keys[i]);
2063 if (key == NULL)
2064 goto out;
2065 value = _dbus_strdup ("Value!");
2066 if (value == NULL)
2067 goto out;
2068
2069 if (!_dbus_hash_table_remove_string (table1, keys[i]))
2070 goto out;
2071
2072 if (!_dbus_hash_table_insert_string (table1,
2073 key, value))
2074 goto out;
2075
2076 if (!_dbus_hash_table_remove_string (table1, keys[i]))
2077 goto out;
2078
2079 _dbus_assert (_dbus_hash_table_get_n_entries (table1) == i);
2080
2081 --i;
2082 }
2083
2084 /* nuke these tables */
2085 _dbus_hash_table_unref (table1);
2086 _dbus_hash_table_unref (table2);
2087
2088
2089 /* Now do a bunch of things again using _dbus_hash_iter_lookup() to
2090 * be sure that interface works.
2091 */
2092 table1 = _dbus_hash_table_new (DBUS_HASH_STRING,
2093 dbus_free, dbus_free);
2094 if (table1 == NULL)
2095 goto out;
2096
2097 table2 = _dbus_hash_table_new (DBUS_HASH_INT,
2098 NULL, dbus_free);
2099 if (table2 == NULL)
2100 goto out;
2101
2102 i = 0;
2103 while (i < 3000)
2104 {
2105 void *value;
2106 char *key;
2107
2108 key = _dbus_strdup (keys[i]);
2109 if (key == NULL)
2110 goto out;
2111 value = _dbus_strdup ("Value!");
2112 if (value == NULL)
2113 goto out;
2114
2115 if (!_dbus_hash_iter_lookup (table1,
2116 key, TRUE, &iter))
2117 goto out;
2118 _dbus_assert (_dbus_hash_iter_get_value (&iter) == NULL);
2119 _dbus_hash_iter_set_value (&iter, value);
2120
2121 value = _dbus_strdup (keys[i]);
2122 if (value == NULL)
2123 goto out;
2124
2125 if (!_dbus_hash_iter_lookup (table2,
2126 _DBUS_INT_TO_POINTER (i), TRUE, &iter))
2127 goto out;
2128 _dbus_assert (_dbus_hash_iter_get_value (&iter) == NULL);
2129 _dbus_hash_iter_set_value (&iter, value);
2130
2131 _dbus_assert (count_entries (table1) == i + 1);
2132 _dbus_assert (count_entries (table2) == i + 1);
2133
2134 if (!_dbus_hash_iter_lookup (table1, keys[i], FALSE, &iter))
2135 goto out;
2136
2137 value = _dbus_hash_iter_get_value (&iter);
2138 _dbus_assert (value != NULL);
2139 _dbus_assert (strcmp (value, "Value!") == 0);
2140
2141 /* Iterate just to be sure it works, though
2142 * it's a stupid thing to do
2143 */
2144 while (_dbus_hash_iter_next (&iter))
2145 ;
2146
2147 if (!_dbus_hash_iter_lookup (table2, _DBUS_INT_TO_POINTER (i), FALSE, &iter))
2148 goto out;
2149
2150 value = _dbus_hash_iter_get_value (&iter);
2151 _dbus_assert (value != NULL);
2152 _dbus_assert (strcmp (value, keys[i]) == 0);
2153
2154 /* Iterate just to be sure it works, though
2155 * it's a stupid thing to do
2156 */
2157 while (_dbus_hash_iter_next (&iter))
2158 ;
2159
2160 ++i;
2161 }
2162
2163 --i;
2164 while (i >= 0)
2165 {
2166 if (!_dbus_hash_iter_lookup (table1, keys[i], FALSE, &iter))
2167 _dbus_assert_not_reached ("hash entry should have existed");
2168 _dbus_hash_iter_remove_entry (&iter);
2169
2170 if (!_dbus_hash_iter_lookup (table2, _DBUS_INT_TO_POINTER (i), FALSE, &iter))
2171 _dbus_assert_not_reached ("hash entry should have existed");
2172 _dbus_hash_iter_remove_entry (&iter);
2173
2174 _dbus_assert (count_entries (table1) == i);
2175 _dbus_assert (count_entries (table2) == i);
2176
2177 --i;
2178 }
2179
2180 _dbus_hash_table_unref (table1);
2181 _dbus_hash_table_unref (table2);
2182
2183 ret = TRUE;
2184
2185 out:
2186 for (i = 0; i < N_HASH_KEYS; i++)
2187 dbus_free (keys[i]);
2188
2189 dbus_free (keys);
2190
2191 return ret;
2192 }
2193
2194 #endif /* DBUS_BUILD_TESTS */
2195