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 _DBUS_STATIC_ASSERT (sizeof (DBusRealHashIter) == sizeof (DBusHashIter)); 226 227 static DBusHashEntry* find_direct_function (DBusHashTable *table, 228 void *key, 229 dbus_bool_t create_if_not_found, 230 DBusHashEntry ***bucket, 231 DBusPreallocatedHash *preallocated); 232 static DBusHashEntry* find_string_function (DBusHashTable *table, 233 void *key, 234 dbus_bool_t create_if_not_found, 235 DBusHashEntry ***bucket, 236 DBusPreallocatedHash *preallocated); 237 static unsigned int string_hash (const char *str); 238 static void rebuild_table (DBusHashTable *table); 239 static DBusHashEntry* alloc_entry (DBusHashTable *table); 240 static void remove_entry (DBusHashTable *table, 241 DBusHashEntry **bucket, 242 DBusHashEntry *entry); 243 static void free_entry (DBusHashTable *table, 244 DBusHashEntry *entry); 245 static void free_entry_data (DBusHashTable *table, 246 DBusHashEntry *entry); 247 248 249 /** @} */ 250 251 /** 252 * @addtogroup DBusHashTable 253 * @{ 254 */ 255 256 /** 257 * @typedef DBusHashIter 258 * 259 * Public opaque hash table iterator object. 260 */ 261 262 /** 263 * @typedef DBusHashTable 264 * 265 * Public opaque hash table object. 266 */ 267 268 /** 269 * @typedef DBusHashType 270 * 271 * Indicates the type of a key in the hash table. 272 */ 273 274 /** 275 * Constructs a new hash table. Should be freed with 276 * _dbus_hash_table_unref(). If memory cannot be 277 * allocated for the hash table, returns #NULL. 278 * 279 * @param type the type of hash key to use. 280 * @param key_free_function function to free hash keys. 281 * @param value_free_function function to free hash values. 282 * @returns a new DBusHashTable or #NULL if no memory. 283 */ 284 DBusHashTable* 285 _dbus_hash_table_new (DBusHashType type, 286 DBusFreeFunction key_free_function, 287 DBusFreeFunction value_free_function) 288 { 289 DBusHashTable *table; 290 DBusMemPool *entry_pool; 291 292 table = dbus_new0 (DBusHashTable, 1); 293 if (table == NULL) 294 return NULL; 295 296 entry_pool = _dbus_mem_pool_new (sizeof (DBusHashEntry), TRUE); 297 if (entry_pool == NULL) 298 { 299 dbus_free (table); 300 return NULL; 301 } 302 303 table->refcount = 1; 304 table->entry_pool = entry_pool; 305 306 _dbus_assert (DBUS_SMALL_HASH_TABLE == _DBUS_N_ELEMENTS (table->static_buckets)); 307 308 table->buckets = table->static_buckets; 309 table->n_buckets = DBUS_SMALL_HASH_TABLE; 310 table->n_entries = 0; 311 table->hi_rebuild_size = DBUS_SMALL_HASH_TABLE * REBUILD_MULTIPLIER; 312 table->lo_rebuild_size = 0; 313 table->down_shift = 28; 314 table->mask = 3; 315 table->key_type = type; 316 317 _dbus_assert (table->mask < table->n_buckets); 318 319 switch (table->key_type) 320 { 321 case DBUS_HASH_INT: 322 case DBUS_HASH_UINTPTR: 323 table->find_function = find_direct_function; 324 break; 325 case DBUS_HASH_STRING: 326 table->find_function = find_string_function; 327 break; 328 default: 329 _dbus_assert_not_reached ("Unknown hash table type"); 330 break; 331 } 332 333 table->free_key_function = key_free_function; 334 table->free_value_function = value_free_function; 335 336 return table; 337 } 338 339 340 /** 341 * Increments the reference count for a hash table. 342 * 343 * @param table the hash table to add a reference to. 344 * @returns the hash table. 345 */ 346 DBusHashTable * 347 _dbus_hash_table_ref (DBusHashTable *table) 348 { 349 table->refcount += 1; 350 351 return table; 352 } 353 354 /** 355 * Decrements the reference count for a hash table, 356 * freeing the hash table if the count reaches zero. 357 * 358 * @param table the hash table to remove a reference from. 359 */ 360 void 361 _dbus_hash_table_unref (DBusHashTable *table) 362 { 363 table->refcount -= 1; 364 365 if (table->refcount == 0) 366 { 367 #if 0 368 DBusHashEntry *entry; 369 DBusHashEntry *next; 370 int i; 371 372 /* Free the entries in the table. */ 373 for (i = 0; i < table->n_buckets; i++) 374 { 375 entry = table->buckets[i]; 376 while (entry != NULL) 377 { 378 next = entry->next; 379 380 free_entry (table, entry); 381 382 entry = next; 383 } 384 } 385 #else 386 DBusHashEntry *entry; 387 int i; 388 389 /* Free the entries in the table. */ 390 for (i = 0; i < table->n_buckets; i++) 391 { 392 entry = table->buckets[i]; 393 while (entry != NULL) 394 { 395 free_entry_data (table, entry); 396 397 entry = entry->next; 398 } 399 } 400 /* We can do this very quickly with memory pools ;-) */ 401 _dbus_mem_pool_free (table->entry_pool); 402 #endif 403 404 /* Free the bucket array, if it was dynamically allocated. */ 405 if (table->buckets != table->static_buckets) 406 dbus_free (table->buckets); 407 408 dbus_free (table); 409 } 410 } 411 412 /** 413 * Removed all entries from a hash table. 414 * 415 * @param table the hash table to remove all entries from. 416 */ 417 void 418 _dbus_hash_table_remove_all (DBusHashTable *table) 419 { 420 DBusHashIter iter; 421 _dbus_hash_iter_init (table, &iter); 422 while (_dbus_hash_iter_next (&iter)) 423 { 424 _dbus_hash_iter_remove_entry(&iter); 425 } 426 } 427 428 static DBusHashEntry* 429 alloc_entry (DBusHashTable *table) 430 { 431 DBusHashEntry *entry; 432 433 entry = _dbus_mem_pool_alloc (table->entry_pool); 434 435 return entry; 436 } 437 438 static void 439 free_entry_data (DBusHashTable *table, 440 DBusHashEntry *entry) 441 { 442 if (table->free_key_function) 443 (* table->free_key_function) (entry->key); 444 if (table->free_value_function) 445 (* table->free_value_function) (entry->value); 446 } 447 448 static void 449 free_entry (DBusHashTable *table, 450 DBusHashEntry *entry) 451 { 452 free_entry_data (table, entry); 453 _dbus_mem_pool_dealloc (table->entry_pool, entry); 454 } 455 456 static void 457 remove_entry (DBusHashTable *table, 458 DBusHashEntry **bucket, 459 DBusHashEntry *entry) 460 { 461 _dbus_assert (table != NULL); 462 _dbus_assert (bucket != NULL); 463 _dbus_assert (*bucket != NULL); 464 _dbus_assert (entry != NULL); 465 466 if (*bucket == entry) 467 *bucket = entry->next; 468 else 469 { 470 DBusHashEntry *prev; 471 prev = *bucket; 472 473 while (prev->next != entry) 474 prev = prev->next; 475 476 _dbus_assert (prev != NULL); 477 478 prev->next = entry->next; 479 } 480 481 table->n_entries -= 1; 482 free_entry (table, entry); 483 } 484 485 /** 486 * Initializes a hash table iterator. To iterate over all entries in a 487 * hash table, use the following code (the printf assumes a hash 488 * from strings to strings obviously): 489 * 490 * @code 491 * DBusHashIter iter; 492 * 493 * _dbus_hash_iter_init (table, &iter); 494 * while (_dbus_hash_iter_next (&iter)) 495 * { 496 * printf ("The first key is %s and value is %s\n", 497 * _dbus_hash_iter_get_string_key (&iter), 498 * _dbus_hash_iter_get_value (&iter)); 499 * } 500 * 501 * 502 * @endcode 503 * 504 * The iterator is initialized pointing "one before" the first hash 505 * entry. The first call to _dbus_hash_iter_next() moves it onto 506 * the first valid entry or returns #FALSE if the hash table is 507 * empty. Subsequent calls move to the next valid entry or return 508 * #FALSE if there are no more entries. 509 * 510 * Note that it is guaranteed to be safe to remove a hash entry during 511 * iteration, but it is not safe to add a hash entry. 512 * 513 * @param table the hash table to iterate over. 514 * @param iter the iterator to initialize. 515 */ 516 void 517 _dbus_hash_iter_init (DBusHashTable *table, 518 DBusHashIter *iter) 519 { 520 DBusRealHashIter *real; 521 522 _dbus_assert (sizeof (DBusHashIter) == sizeof (DBusRealHashIter)); 523 524 real = (DBusRealHashIter*) iter; 525 526 real->table = table; 527 real->bucket = NULL; 528 real->entry = NULL; 529 real->next_entry = NULL; 530 real->next_bucket = 0; 531 real->n_entries_on_init = table->n_entries; 532 } 533 534 /** 535 * Move the hash iterator forward one step, to the next hash entry. 536 * The documentation for _dbus_hash_iter_init() explains in more 537 * detail. 538 * 539 * @param iter the iterator to move forward. 540 * @returns #FALSE if there are no more entries to move to. 541 */ 542 dbus_bool_t 543 _dbus_hash_iter_next (DBusHashIter *iter) 544 { 545 DBusRealHashIter *real; 546 547 _dbus_assert (sizeof (DBusHashIter) == sizeof (DBusRealHashIter)); 548 549 real = (DBusRealHashIter*) iter; 550 551 /* if this assertion failed someone probably added hash entries 552 * during iteration, which is bad. 553 */ 554 _dbus_assert (real->n_entries_on_init >= real->table->n_entries); 555 556 /* Remember that real->entry may have been deleted */ 557 558 while (real->next_entry == NULL) 559 { 560 if (real->next_bucket >= real->table->n_buckets) 561 { 562 /* invalidate iter and return false */ 563 real->entry = NULL; 564 real->table = NULL; 565 real->bucket = NULL; 566 return FALSE; 567 } 568 569 real->bucket = &(real->table->buckets[real->next_bucket]); 570 real->next_entry = *(real->bucket); 571 real->next_bucket += 1; 572 } 573 574 _dbus_assert (real->next_entry != NULL); 575 _dbus_assert (real->bucket != NULL); 576 577 real->entry = real->next_entry; 578 real->next_entry = real->entry->next; 579 580 return TRUE; 581 } 582 583 /** 584 * Removes the current entry from the hash table. 585 * If a key_free_function or value_free_function 586 * was provided to _dbus_hash_table_new(), 587 * frees the key and/or value for this entry. 588 * 589 * @param iter the hash table iterator. 590 */ 591 void 592 _dbus_hash_iter_remove_entry (DBusHashIter *iter) 593 { 594 DBusRealHashIter *real; 595 596 real = (DBusRealHashIter*) iter; 597 598 _dbus_assert (real->table != NULL); 599 _dbus_assert (real->entry != NULL); 600 _dbus_assert (real->bucket != NULL); 601 602 remove_entry (real->table, real->bucket, real->entry); 603 604 real->entry = NULL; /* make it crash if you try to use this entry */ 605 } 606 607 /** 608 * Gets the value of the current entry. 609 * 610 * @param iter the hash table iterator. 611 */ 612 void* 613 _dbus_hash_iter_get_value (DBusHashIter *iter) 614 { 615 DBusRealHashIter *real; 616 617 real = (DBusRealHashIter*) iter; 618 619 _dbus_assert (real->table != NULL); 620 _dbus_assert (real->entry != NULL); 621 622 return real->entry->value; 623 } 624 625 /** 626 * Sets the value of the current entry. 627 * If the hash table has a value_free_function 628 * it will be used to free the previous value. 629 * The hash table will own the passed-in value 630 * (it will not be copied). 631 * 632 * @param iter the hash table iterator. 633 * @param value the new value. 634 */ 635 void 636 _dbus_hash_iter_set_value (DBusHashIter *iter, 637 void *value) 638 { 639 DBusRealHashIter *real; 640 641 real = (DBusRealHashIter*) iter; 642 643 _dbus_assert (real->table != NULL); 644 _dbus_assert (real->entry != NULL); 645 646 if (real->table->free_value_function && value != real->entry->value) 647 (* real->table->free_value_function) (real->entry->value); 648 649 real->entry->value = value; 650 } 651 652 /** 653 * Gets the key for the current entry. 654 * Only works for hash tables of type #DBUS_HASH_INT. 655 * 656 * @param iter the hash table iterator. 657 */ 658 int 659 _dbus_hash_iter_get_int_key (DBusHashIter *iter) 660 { 661 DBusRealHashIter *real; 662 663 real = (DBusRealHashIter*) iter; 664 665 _dbus_assert (real->table != NULL); 666 _dbus_assert (real->entry != NULL); 667 668 return _DBUS_POINTER_TO_INT (real->entry->key); 669 } 670 671 /** 672 * Gets the key for the current entry. 673 * Only works for hash tables of type #DBUS_HASH_UINTPTR. 674 * 675 * @param iter the hash table iterator. 676 */ 677 uintptr_t 678 _dbus_hash_iter_get_uintptr_key (DBusHashIter *iter) 679 { 680 DBusRealHashIter *real; 681 682 real = (DBusRealHashIter*) iter; 683 684 _dbus_assert (real->table != NULL); 685 _dbus_assert (real->entry != NULL); 686 687 return (uintptr_t) real->entry->key; 688 } 689 690 /** 691 * Gets the key for the current entry. 692 * Only works for hash tables of type #DBUS_HASH_STRING 693 * @param iter the hash table iterator. 694 */ 695 const char* 696 _dbus_hash_iter_get_string_key (DBusHashIter *iter) 697 { 698 DBusRealHashIter *real; 699 700 real = (DBusRealHashIter*) iter; 701 702 _dbus_assert (real->table != NULL); 703 _dbus_assert (real->entry != NULL); 704 705 return real->entry->key; 706 } 707 708 /** 709 * A low-level but efficient interface for manipulating the hash 710 * table. It's efficient because you can get, set, and optionally 711 * create the hash entry while only running the hash function one 712 * time. 713 * 714 * Note that while calling _dbus_hash_iter_next() on the iterator 715 * filled in by this function may work, it's completely 716 * undefined which entries are after this iter and which 717 * are before it. So it would be silly to iterate using this 718 * iterator. 719 * 720 * If the hash entry is created, its value will be initialized 721 * to all bits zero. 722 * 723 * #FALSE may be returned due to memory allocation failure, or 724 * because create_if_not_found was #FALSE and the entry 725 * did not exist. 726 * 727 * If create_if_not_found is #TRUE and the entry is created, the hash 728 * table takes ownership of the key that's passed in. 729 * 730 * For a hash table of type #DBUS_HASH_INT, cast the int 731 * key to the key parameter using #_DBUS_INT_TO_POINTER(). 732 * 733 * @param table the hash table. 734 * @param key the hash key. 735 * @param create_if_not_found if #TRUE, create the entry if it didn't exist. 736 * @param iter the iterator to initialize. 737 * @returns #TRUE if the hash entry now exists (and the iterator is thus valid). 738 */ 739 dbus_bool_t 740 _dbus_hash_iter_lookup (DBusHashTable *table, 741 void *key, 742 dbus_bool_t create_if_not_found, 743 DBusHashIter *iter) 744 { 745 DBusRealHashIter *real; 746 DBusHashEntry *entry; 747 DBusHashEntry **bucket; 748 749 _dbus_assert (sizeof (DBusHashIter) == sizeof (DBusRealHashIter)); 750 751 real = (DBusRealHashIter*) iter; 752 753 entry = (* table->find_function) (table, key, create_if_not_found, &bucket, NULL); 754 755 if (entry == NULL) 756 return FALSE; 757 758 real->table = table; 759 real->bucket = bucket; 760 real->entry = entry; 761 real->next_entry = entry->next; 762 real->next_bucket = (bucket - table->buckets) + 1; 763 real->n_entries_on_init = table->n_entries; 764 765 _dbus_assert (&(table->buckets[real->next_bucket-1]) == real->bucket); 766 767 return TRUE; 768 } 769 770 static void 771 add_allocated_entry (DBusHashTable *table, 772 DBusHashEntry *entry, 773 unsigned int idx, 774 void *key, 775 DBusHashEntry ***bucket) 776 { 777 DBusHashEntry **b; 778 779 entry->key = key; 780 781 b = &(table->buckets[idx]); 782 entry->next = *b; 783 *b = entry; 784 785 if (bucket) 786 *bucket = b; 787 788 table->n_entries += 1; 789 790 /* note we ONLY rebuild when ADDING - because you can iterate over a 791 * table and remove entries safely. 792 */ 793 if (table->n_entries >= table->hi_rebuild_size || 794 table->n_entries < table->lo_rebuild_size) 795 rebuild_table (table); 796 } 797 798 static DBusHashEntry* 799 add_entry (DBusHashTable *table, 800 unsigned int idx, 801 void *key, 802 DBusHashEntry ***bucket, 803 DBusPreallocatedHash *preallocated) 804 { 805 DBusHashEntry *entry; 806 807 if (preallocated == NULL) 808 { 809 entry = alloc_entry (table); 810 if (entry == NULL) 811 { 812 if (bucket) 813 *bucket = NULL; 814 return NULL; 815 } 816 } 817 else 818 { 819 entry = (DBusHashEntry*) preallocated; 820 } 821 822 add_allocated_entry (table, entry, idx, key, bucket); 823 824 return entry; 825 } 826 827 /* This is g_str_hash from GLib which was 828 * extensively discussed/tested/profiled 829 */ 830 static unsigned int 831 string_hash (const char *str) 832 { 833 const char *p = str; 834 unsigned int h = *p; 835 836 if (h) 837 for (p += 1; *p != '\0'; p++) 838 h = (h << 5) - h + *p; 839 840 return h; 841 } 842 843 /** Key comparison function */ 844 typedef int (* KeyCompareFunc) (const void *key_a, const void *key_b); 845 846 static DBusHashEntry* 847 find_generic_function (DBusHashTable *table, 848 void *key, 849 unsigned int idx, 850 KeyCompareFunc compare_func, 851 dbus_bool_t create_if_not_found, 852 DBusHashEntry ***bucket, 853 DBusPreallocatedHash *preallocated) 854 { 855 DBusHashEntry *entry; 856 857 if (bucket) 858 *bucket = NULL; 859 860 /* Search all of the entries in this bucket. */ 861 entry = table->buckets[idx]; 862 while (entry != NULL) 863 { 864 if ((compare_func == NULL && key == entry->key) || 865 (compare_func != NULL && (* compare_func) (key, entry->key) == 0)) 866 { 867 if (bucket) 868 *bucket = &(table->buckets[idx]); 869 870 if (preallocated) 871 _dbus_hash_table_free_preallocated_entry (table, preallocated); 872 873 return entry; 874 } 875 876 entry = entry->next; 877 } 878 879 if (create_if_not_found) 880 entry = add_entry (table, idx, key, bucket, preallocated); 881 else if (preallocated) 882 _dbus_hash_table_free_preallocated_entry (table, preallocated); 883 884 return entry; 885 } 886 887 static DBusHashEntry* 888 find_string_function (DBusHashTable *table, 889 void *key, 890 dbus_bool_t create_if_not_found, 891 DBusHashEntry ***bucket, 892 DBusPreallocatedHash *preallocated) 893 { 894 unsigned int idx; 895 896 idx = string_hash (key) & table->mask; 897 898 return find_generic_function (table, key, idx, 899 (KeyCompareFunc) strcmp, create_if_not_found, bucket, 900 preallocated); 901 } 902 903 static DBusHashEntry* 904 find_direct_function (DBusHashTable *table, 905 void *key, 906 dbus_bool_t create_if_not_found, 907 DBusHashEntry ***bucket, 908 DBusPreallocatedHash *preallocated) 909 { 910 unsigned int idx; 911 912 idx = RANDOM_INDEX (table, key) & table->mask; 913 914 915 return find_generic_function (table, key, idx, 916 NULL, create_if_not_found, bucket, 917 preallocated); 918 } 919 920 static void 921 rebuild_table (DBusHashTable *table) 922 { 923 int old_size; 924 int new_buckets; 925 DBusHashEntry **old_buckets; 926 DBusHashEntry **old_chain; 927 DBusHashEntry *entry; 928 dbus_bool_t growing; 929 930 /* 931 * Allocate and initialize the new bucket array, and set up 932 * hashing constants for new array size. 933 */ 934 935 growing = table->n_entries >= table->hi_rebuild_size; 936 937 old_size = table->n_buckets; 938 old_buckets = table->buckets; 939 940 if (growing) 941 { 942 /* overflow paranoia */ 943 if (table->n_buckets < _DBUS_INT_MAX / 4 && 944 table->down_shift >= 0) 945 new_buckets = table->n_buckets * 4; 946 else 947 return; /* can't grow anymore */ 948 } 949 else 950 { 951 new_buckets = table->n_buckets / 4; 952 if (new_buckets < DBUS_SMALL_HASH_TABLE) 953 return; /* don't bother shrinking this far */ 954 } 955 956 table->buckets = dbus_new0 (DBusHashEntry*, new_buckets); 957 if (table->buckets == NULL) 958 { 959 /* out of memory, yay - just don't reallocate, the table will 960 * still work, albeit more slowly. 961 */ 962 table->buckets = old_buckets; 963 return; 964 } 965 966 table->n_buckets = new_buckets; 967 968 if (growing) 969 { 970 table->lo_rebuild_size = table->hi_rebuild_size; 971 table->hi_rebuild_size *= 4; 972 973 table->down_shift -= 2; /* keep 2 more high bits */ 974 table->mask = (table->mask << 2) + 3; /* keep 2 more high bits */ 975 } 976 else 977 { 978 table->hi_rebuild_size = table->lo_rebuild_size; 979 table->lo_rebuild_size /= 4; 980 981 table->down_shift += 2; /* keep 2 fewer high bits */ 982 table->mask = table->mask >> 2; /* keep 2 fewer high bits */ 983 } 984 985 #if 0 986 printf ("%s table to lo = %d hi = %d downshift = %d mask = 0x%x\n", 987 growing ? "GROW" : "SHRINK", 988 table->lo_rebuild_size, 989 table->hi_rebuild_size, 990 table->down_shift, 991 table->mask); 992 #endif 993 994 _dbus_assert (table->lo_rebuild_size >= 0); 995 _dbus_assert (table->hi_rebuild_size > table->lo_rebuild_size); 996 _dbus_assert (table->mask != 0); 997 /* the mask is essentially the max index */ 998 _dbus_assert (table->mask < table->n_buckets); 999 1000 /* 1001 * Rehash all of the existing entries into the new bucket array. 1002 */ 1003 1004 for (old_chain = old_buckets; old_size > 0; old_size--, old_chain++) 1005 { 1006 for (entry = *old_chain; entry != NULL; entry = *old_chain) 1007 { 1008 unsigned int idx; 1009 DBusHashEntry **bucket; 1010 1011 *old_chain = entry->next; 1012 switch (table->key_type) 1013 { 1014 case DBUS_HASH_STRING: 1015 idx = string_hash (entry->key) & table->mask; 1016 break; 1017 case DBUS_HASH_INT: 1018 case DBUS_HASH_UINTPTR: 1019 idx = RANDOM_INDEX (table, entry->key); 1020 break; 1021 default: 1022 idx = 0; 1023 _dbus_assert_not_reached ("Unknown hash table type"); 1024 break; 1025 } 1026 1027 bucket = &(table->buckets[idx]); 1028 entry->next = *bucket; 1029 *bucket = entry; 1030 } 1031 } 1032 1033 /* Free the old bucket array, if it was dynamically allocated. */ 1034 1035 if (old_buckets != table->static_buckets) 1036 dbus_free (old_buckets); 1037 } 1038 1039 /** 1040 * Looks up the value for a given string in a hash table 1041 * of type #DBUS_HASH_STRING. Returns %NULL if the value 1042 * is not present. (A not-present entry is indistinguishable 1043 * from an entry with a value of %NULL.) 1044 * @param table the hash table. 1045 * @param key the string to look up. 1046 * @returns the value of the hash entry. 1047 */ 1048 void* 1049 _dbus_hash_table_lookup_string (DBusHashTable *table, 1050 const char *key) 1051 { 1052 DBusHashEntry *entry; 1053 1054 _dbus_assert (table->key_type == DBUS_HASH_STRING); 1055 1056 entry = (* table->find_function) (table, (char*) key, FALSE, NULL, NULL); 1057 1058 if (entry) 1059 return entry->value; 1060 else 1061 return NULL; 1062 } 1063 1064 /** 1065 * Looks up the value for a given integer in a hash table 1066 * of type #DBUS_HASH_INT. Returns %NULL if the value 1067 * is not present. (A not-present entry is indistinguishable 1068 * from an entry with a value of %NULL.) 1069 * @param table the hash table. 1070 * @param key the integer to look up. 1071 * @returns the value of the hash entry. 1072 */ 1073 void* 1074 _dbus_hash_table_lookup_int (DBusHashTable *table, 1075 int key) 1076 { 1077 DBusHashEntry *entry; 1078 1079 _dbus_assert (table->key_type == DBUS_HASH_INT); 1080 1081 entry = (* table->find_function) (table, _DBUS_INT_TO_POINTER (key), FALSE, NULL, NULL); 1082 1083 if (entry) 1084 return entry->value; 1085 else 1086 return NULL; 1087 } 1088 1089 /** 1090 * Looks up the value for a given integer in a hash table 1091 * of type #DBUS_HASH_UINTPTR. Returns %NULL if the value 1092 * is not present. (A not-present entry is indistinguishable 1093 * from an entry with a value of %NULL.) 1094 * @param table the hash table. 1095 * @param key the integer to look up. 1096 * @returns the value of the hash entry. 1097 */ 1098 void* 1099 _dbus_hash_table_lookup_uintptr (DBusHashTable *table, 1100 uintptr_t key) 1101 { 1102 DBusHashEntry *entry; 1103 1104 _dbus_assert (table->key_type == DBUS_HASH_UINTPTR); 1105 1106 entry = (* table->find_function) (table, (void*) key, FALSE, NULL, NULL); 1107 1108 if (entry) 1109 return entry->value; 1110 else 1111 return NULL; 1112 } 1113 1114 /** 1115 * Removes the hash entry for the given key. If no hash entry 1116 * for the key exists, does nothing. 1117 * 1118 * @param table the hash table. 1119 * @param key the hash key. 1120 * @returns #TRUE if the entry existed 1121 */ 1122 dbus_bool_t 1123 _dbus_hash_table_remove_string (DBusHashTable *table, 1124 const char *key) 1125 { 1126 DBusHashEntry *entry; 1127 DBusHashEntry **bucket; 1128 1129 _dbus_assert (table->key_type == DBUS_HASH_STRING); 1130 1131 entry = (* table->find_function) (table, (char*) key, FALSE, &bucket, NULL); 1132 1133 if (entry) 1134 { 1135 remove_entry (table, bucket, entry); 1136 return TRUE; 1137 } 1138 else 1139 return FALSE; 1140 } 1141 1142 /** 1143 * Removes the hash entry for the given key. If no hash entry 1144 * for the key exists, does nothing. 1145 * 1146 * @param table the hash table. 1147 * @param key the hash key. 1148 * @returns #TRUE if the entry existed 1149 */ 1150 dbus_bool_t 1151 _dbus_hash_table_remove_int (DBusHashTable *table, 1152 int key) 1153 { 1154 DBusHashEntry *entry; 1155 DBusHashEntry **bucket; 1156 1157 _dbus_assert (table->key_type == DBUS_HASH_INT); 1158 1159 entry = (* table->find_function) (table, _DBUS_INT_TO_POINTER (key), FALSE, &bucket, NULL); 1160 1161 if (entry) 1162 { 1163 remove_entry (table, bucket, entry); 1164 return TRUE; 1165 } 1166 else 1167 return FALSE; 1168 } 1169 1170 /** 1171 * Removes the hash entry for the given key. If no hash entry 1172 * for the key exists, does nothing. 1173 * 1174 * @param table the hash table. 1175 * @param key the hash key. 1176 * @returns #TRUE if the entry existed 1177 */ 1178 dbus_bool_t 1179 _dbus_hash_table_remove_uintptr (DBusHashTable *table, 1180 uintptr_t key) 1181 { 1182 DBusHashEntry *entry; 1183 DBusHashEntry **bucket; 1184 1185 _dbus_assert (table->key_type == DBUS_HASH_UINTPTR); 1186 1187 entry = (* table->find_function) (table, (void*) key, FALSE, &bucket, NULL); 1188 1189 if (entry) 1190 { 1191 remove_entry (table, bucket, entry); 1192 return TRUE; 1193 } 1194 else 1195 return FALSE; 1196 } 1197 1198 /** 1199 * Creates a hash entry with the given key and value. 1200 * The key and value are not copied; they are stored 1201 * in the hash table by reference. If an entry with the 1202 * given key already exists, the previous key and value 1203 * are overwritten (and freed if the hash table has 1204 * a key_free_function and/or value_free_function). 1205 * 1206 * Returns #FALSE if memory for the new hash entry 1207 * can't be allocated. 1208 * 1209 * @param table the hash table. 1210 * @param key the hash entry key. 1211 * @param value the hash entry value. 1212 */ 1213 dbus_bool_t 1214 _dbus_hash_table_insert_string (DBusHashTable *table, 1215 char *key, 1216 void *value) 1217 { 1218 DBusPreallocatedHash *preallocated; 1219 1220 _dbus_assert (table->key_type == DBUS_HASH_STRING); 1221 1222 preallocated = _dbus_hash_table_preallocate_entry (table); 1223 if (preallocated == NULL) 1224 return FALSE; 1225 1226 _dbus_hash_table_insert_string_preallocated (table, preallocated, 1227 key, value); 1228 1229 return TRUE; 1230 } 1231 1232 /** 1233 * Creates a hash entry with the given key and value. 1234 * The key and value are not copied; they are stored 1235 * in the hash table by reference. If an entry with the 1236 * given key already exists, the previous key and value 1237 * are overwritten (and freed if the hash table has 1238 * a key_free_function and/or value_free_function). 1239 * 1240 * Returns #FALSE if memory for the new hash entry 1241 * can't be allocated. 1242 * 1243 * @param table the hash table. 1244 * @param key the hash entry key. 1245 * @param value the hash entry value. 1246 */ 1247 dbus_bool_t 1248 _dbus_hash_table_insert_int (DBusHashTable *table, 1249 int key, 1250 void *value) 1251 { 1252 DBusHashEntry *entry; 1253 1254 _dbus_assert (table->key_type == DBUS_HASH_INT); 1255 1256 entry = (* table->find_function) (table, _DBUS_INT_TO_POINTER (key), TRUE, NULL, NULL); 1257 1258 if (entry == NULL) 1259 return FALSE; /* no memory */ 1260 1261 if (table->free_key_function && entry->key != _DBUS_INT_TO_POINTER (key)) 1262 (* table->free_key_function) (entry->key); 1263 1264 if (table->free_value_function && entry->value != value) 1265 (* table->free_value_function) (entry->value); 1266 1267 entry->key = _DBUS_INT_TO_POINTER (key); 1268 entry->value = value; 1269 1270 return TRUE; 1271 } 1272 1273 /** 1274 * Creates a hash entry with the given key and value. 1275 * The key and value are not copied; they are stored 1276 * in the hash table by reference. If an entry with the 1277 * given key already exists, the previous key and value 1278 * are overwritten (and freed if the hash table has 1279 * a key_free_function and/or value_free_function). 1280 * 1281 * Returns #FALSE if memory for the new hash entry 1282 * can't be allocated. 1283 * 1284 * @param table the hash table. 1285 * @param key the hash entry key. 1286 * @param value the hash entry value. 1287 */ 1288 dbus_bool_t 1289 _dbus_hash_table_insert_uintptr (DBusHashTable *table, 1290 uintptr_t key, 1291 void *value) 1292 { 1293 DBusHashEntry *entry; 1294 1295 _dbus_assert (table->key_type == DBUS_HASH_UINTPTR); 1296 1297 entry = (* table->find_function) (table, (void*) key, TRUE, NULL, NULL); 1298 1299 if (entry == NULL) 1300 return FALSE; /* no memory */ 1301 1302 if (table->free_key_function && entry->key != (void*) key) 1303 (* table->free_key_function) (entry->key); 1304 1305 if (table->free_value_function && entry->value != value) 1306 (* table->free_value_function) (entry->value); 1307 1308 entry->key = (void*) key; 1309 entry->value = value; 1310 1311 return TRUE; 1312 } 1313 1314 /** 1315 * Preallocate an opaque data blob that allows us to insert into the 1316 * hash table at a later time without allocating any memory. 1317 * 1318 * @param table the hash table 1319 * @returns the preallocated data, or #NULL if no memory 1320 */ 1321 DBusPreallocatedHash* 1322 _dbus_hash_table_preallocate_entry (DBusHashTable *table) 1323 { 1324 DBusHashEntry *entry; 1325 1326 entry = alloc_entry (table); 1327 1328 return (DBusPreallocatedHash*) entry; 1329 } 1330 1331 /** 1332 * Frees an opaque DBusPreallocatedHash that was *not* used 1333 * in order to insert into the hash table. 1334 * 1335 * @param table the hash table 1336 * @param preallocated the preallocated data 1337 */ 1338 void 1339 _dbus_hash_table_free_preallocated_entry (DBusHashTable *table, 1340 DBusPreallocatedHash *preallocated) 1341 { 1342 DBusHashEntry *entry; 1343 1344 _dbus_assert (preallocated != NULL); 1345 1346 entry = (DBusHashEntry*) preallocated; 1347 1348 /* Don't use free_entry(), since this entry has no key/data */ 1349 _dbus_mem_pool_dealloc (table->entry_pool, entry); 1350 } 1351 1352 /** 1353 * Inserts a string-keyed entry into the hash table, using a 1354 * preallocated data block from 1355 * _dbus_hash_table_preallocate_entry(). This function cannot fail due 1356 * to lack of memory. The DBusPreallocatedHash object is consumed and 1357 * should not be reused or freed. Otherwise this function works 1358 * just like _dbus_hash_table_insert_string(). 1359 * 1360 * @param table the hash table 1361 * @param preallocated the preallocated data 1362 * @param key the hash key 1363 * @param value the value 1364 */ 1365 void 1366 _dbus_hash_table_insert_string_preallocated (DBusHashTable *table, 1367 DBusPreallocatedHash *preallocated, 1368 char *key, 1369 void *value) 1370 { 1371 DBusHashEntry *entry; 1372 1373 _dbus_assert (table->key_type == DBUS_HASH_STRING); 1374 _dbus_assert (preallocated != NULL); 1375 1376 entry = (* table->find_function) (table, key, TRUE, NULL, preallocated); 1377 1378 _dbus_assert (entry != NULL); 1379 1380 if (table->free_key_function && entry->key != key) 1381 (* table->free_key_function) (entry->key); 1382 1383 if (table->free_value_function && entry->value != value) 1384 (* table->free_value_function) (entry->value); 1385 1386 entry->key = key; 1387 entry->value = value; 1388 } 1389 1390 /** 1391 * Gets the number of hash entries in a hash table. 1392 * 1393 * @param table the hash table. 1394 * @returns the number of entries in the table. 1395 */ 1396 int 1397 _dbus_hash_table_get_n_entries (DBusHashTable *table) 1398 { 1399 return table->n_entries; 1400 } 1401 1402 /** @} */ 1403 1404 #ifdef DBUS_BUILD_TESTS 1405 #include "dbus-test.h" 1406 #include <stdio.h> 1407 1408 /* If you're wondering why the hash table test takes 1409 * forever to run, it's because we call this function 1410 * in inner loops thus making things quadratic. 1411 */ 1412 static int 1413 count_entries (DBusHashTable *table) 1414 { 1415 DBusHashIter iter; 1416 int count; 1417 1418 count = 0; 1419 _dbus_hash_iter_init (table, &iter); 1420 while (_dbus_hash_iter_next (&iter)) 1421 ++count; 1422 1423 _dbus_assert (count == _dbus_hash_table_get_n_entries (table)); 1424 1425 return count; 1426 } 1427 1428 /** 1429 * @ingroup DBusHashTableInternals 1430 * Unit test for DBusHashTable 1431 * @returns #TRUE on success. 1432 */ 1433 dbus_bool_t 1434 _dbus_hash_test (void) 1435 { 1436 int i; 1437 DBusHashTable *table1; 1438 DBusHashTable *table2; 1439 DBusHashTable *table3; 1440 DBusHashIter iter; 1441 #define N_HASH_KEYS 5000 1442 char **keys; 1443 dbus_bool_t ret = FALSE; 1444 1445 keys = dbus_new (char *, N_HASH_KEYS); 1446 if (keys == NULL) 1447 _dbus_assert_not_reached ("no memory"); 1448 1449 for (i = 0; i < N_HASH_KEYS; i++) 1450 { 1451 keys[i] = dbus_malloc (128); 1452 1453 if (keys[i] == NULL) 1454 _dbus_assert_not_reached ("no memory"); 1455 } 1456 1457 printf ("Computing test hash keys...\n"); 1458 i = 0; 1459 while (i < N_HASH_KEYS) 1460 { 1461 int len; 1462 1463 len = sprintf (keys[i], "Hash key %d", i); 1464 _dbus_assert (*(keys[i] + len) == '\0'); 1465 ++i; 1466 } 1467 printf ("... done.\n"); 1468 1469 table1 = _dbus_hash_table_new (DBUS_HASH_STRING, 1470 dbus_free, dbus_free); 1471 if (table1 == NULL) 1472 goto out; 1473 1474 table2 = _dbus_hash_table_new (DBUS_HASH_INT, 1475 NULL, dbus_free); 1476 if (table2 == NULL) 1477 goto out; 1478 1479 table3 = _dbus_hash_table_new (DBUS_HASH_UINTPTR, 1480 NULL, dbus_free); 1481 if (table3 == NULL) 1482 goto out; 1483 1484 /* Insert and remove a bunch of stuff, counting the table in between 1485 * to be sure it's not broken and that iteration works 1486 */ 1487 i = 0; 1488 while (i < 3000) 1489 { 1490 void *value; 1491 char *key; 1492 1493 key = _dbus_strdup (keys[i]); 1494 if (key == NULL) 1495 goto out; 1496 value = _dbus_strdup ("Value!"); 1497 if (value == NULL) 1498 goto out; 1499 1500 if (!_dbus_hash_table_insert_string (table1, 1501 key, value)) 1502 goto out; 1503 1504 value = _dbus_strdup (keys[i]); 1505 if (value == NULL) 1506 goto out; 1507 1508 if (!_dbus_hash_table_insert_int (table2, 1509 i, value)) 1510 goto out; 1511 1512 value = _dbus_strdup (keys[i]); 1513 if (value == NULL) 1514 goto out; 1515 1516 if (!_dbus_hash_table_insert_uintptr (table3, 1517 i, value)) 1518 goto out; 1519 1520 _dbus_assert (count_entries (table1) == i + 1); 1521 _dbus_assert (count_entries (table2) == i + 1); 1522 _dbus_assert (count_entries (table3) == i + 1); 1523 1524 value = _dbus_hash_table_lookup_string (table1, keys[i]); 1525 _dbus_assert (value != NULL); 1526 _dbus_assert (strcmp (value, "Value!") == 0); 1527 1528 value = _dbus_hash_table_lookup_int (table2, i); 1529 _dbus_assert (value != NULL); 1530 _dbus_assert (strcmp (value, keys[i]) == 0); 1531 1532 value = _dbus_hash_table_lookup_uintptr (table3, i); 1533 _dbus_assert (value != NULL); 1534 _dbus_assert (strcmp (value, keys[i]) == 0); 1535 1536 ++i; 1537 } 1538 1539 --i; 1540 while (i >= 0) 1541 { 1542 _dbus_hash_table_remove_string (table1, 1543 keys[i]); 1544 1545 _dbus_hash_table_remove_int (table2, i); 1546 1547 _dbus_hash_table_remove_uintptr (table3, i); 1548 1549 _dbus_assert (count_entries (table1) == i); 1550 _dbus_assert (count_entries (table2) == i); 1551 _dbus_assert (count_entries (table3) == i); 1552 1553 --i; 1554 } 1555 1556 _dbus_hash_table_ref (table1); 1557 _dbus_hash_table_ref (table2); 1558 _dbus_hash_table_ref (table3); 1559 _dbus_hash_table_unref (table1); 1560 _dbus_hash_table_unref (table2); 1561 _dbus_hash_table_unref (table3); 1562 _dbus_hash_table_unref (table1); 1563 _dbus_hash_table_unref (table2); 1564 _dbus_hash_table_unref (table3); 1565 table3 = NULL; 1566 1567 /* Insert a bunch of stuff then check 1568 * that iteration works correctly (finds the right 1569 * values, iter_set_value works, etc.) 1570 */ 1571 table1 = _dbus_hash_table_new (DBUS_HASH_STRING, 1572 dbus_free, dbus_free); 1573 if (table1 == NULL) 1574 goto out; 1575 1576 table2 = _dbus_hash_table_new (DBUS_HASH_INT, 1577 NULL, dbus_free); 1578 if (table2 == NULL) 1579 goto out; 1580 1581 i = 0; 1582 while (i < 5000) 1583 { 1584 char *key; 1585 void *value; 1586 1587 key = _dbus_strdup (keys[i]); 1588 if (key == NULL) 1589 goto out; 1590 value = _dbus_strdup ("Value!"); 1591 if (value == NULL) 1592 goto out; 1593 1594 if (!_dbus_hash_table_insert_string (table1, 1595 key, value)) 1596 goto out; 1597 1598 value = _dbus_strdup (keys[i]); 1599 if (value == NULL) 1600 goto out; 1601 1602 if (!_dbus_hash_table_insert_int (table2, 1603 i, value)) 1604 goto out; 1605 1606 _dbus_assert (count_entries (table1) == i + 1); 1607 _dbus_assert (count_entries (table2) == i + 1); 1608 1609 ++i; 1610 } 1611 1612 _dbus_hash_iter_init (table1, &iter); 1613 while (_dbus_hash_iter_next (&iter)) 1614 { 1615 const char *key; 1616 void *value; 1617 1618 key = _dbus_hash_iter_get_string_key (&iter); 1619 value = _dbus_hash_iter_get_value (&iter); 1620 1621 _dbus_assert (_dbus_hash_table_lookup_string (table1, key) == value); 1622 1623 value = _dbus_strdup ("Different value!"); 1624 if (value == NULL) 1625 goto out; 1626 1627 _dbus_hash_iter_set_value (&iter, value); 1628 1629 _dbus_assert (_dbus_hash_table_lookup_string (table1, key) == value); 1630 } 1631 1632 _dbus_hash_iter_init (table1, &iter); 1633 while (_dbus_hash_iter_next (&iter)) 1634 { 1635 _dbus_hash_iter_remove_entry (&iter); 1636 _dbus_assert (count_entries (table1) == i - 1); 1637 --i; 1638 } 1639 1640 _dbus_hash_iter_init (table2, &iter); 1641 while (_dbus_hash_iter_next (&iter)) 1642 { 1643 int key; 1644 void *value; 1645 1646 key = _dbus_hash_iter_get_int_key (&iter); 1647 value = _dbus_hash_iter_get_value (&iter); 1648 1649 _dbus_assert (_dbus_hash_table_lookup_int (table2, key) == value); 1650 1651 value = _dbus_strdup ("Different value!"); 1652 if (value == NULL) 1653 goto out; 1654 1655 _dbus_hash_iter_set_value (&iter, value); 1656 1657 _dbus_assert (_dbus_hash_table_lookup_int (table2, key) == value); 1658 } 1659 1660 i = count_entries (table2); 1661 _dbus_hash_iter_init (table2, &iter); 1662 while (_dbus_hash_iter_next (&iter)) 1663 { 1664 _dbus_hash_iter_remove_entry (&iter); 1665 _dbus_assert (count_entries (table2) + 1 == i); 1666 --i; 1667 } 1668 1669 /* add/remove interleaved, to check that we grow/shrink the table 1670 * appropriately 1671 */ 1672 i = 0; 1673 while (i < 1000) 1674 { 1675 char *key; 1676 void *value; 1677 1678 key = _dbus_strdup (keys[i]); 1679 if (key == NULL) 1680 goto out; 1681 1682 value = _dbus_strdup ("Value!"); 1683 if (value == NULL) 1684 goto out; 1685 1686 if (!_dbus_hash_table_insert_string (table1, 1687 key, value)) 1688 goto out; 1689 1690 ++i; 1691 } 1692 1693 --i; 1694 while (i >= 0) 1695 { 1696 char *key; 1697 void *value; 1698 1699 key = _dbus_strdup (keys[i]); 1700 if (key == NULL) 1701 goto out; 1702 value = _dbus_strdup ("Value!"); 1703 if (value == NULL) 1704 goto out; 1705 1706 if (!_dbus_hash_table_remove_string (table1, keys[i])) 1707 goto out; 1708 1709 if (!_dbus_hash_table_insert_string (table1, 1710 key, value)) 1711 goto out; 1712 1713 if (!_dbus_hash_table_remove_string (table1, keys[i])) 1714 goto out; 1715 1716 _dbus_assert (_dbus_hash_table_get_n_entries (table1) == i); 1717 1718 --i; 1719 } 1720 1721 /* nuke these tables */ 1722 _dbus_hash_table_unref (table1); 1723 _dbus_hash_table_unref (table2); 1724 1725 1726 /* Now do a bunch of things again using _dbus_hash_iter_lookup() to 1727 * be sure that interface works. 1728 */ 1729 table1 = _dbus_hash_table_new (DBUS_HASH_STRING, 1730 dbus_free, dbus_free); 1731 if (table1 == NULL) 1732 goto out; 1733 1734 table2 = _dbus_hash_table_new (DBUS_HASH_INT, 1735 NULL, dbus_free); 1736 if (table2 == NULL) 1737 goto out; 1738 1739 i = 0; 1740 while (i < 3000) 1741 { 1742 void *value; 1743 char *key; 1744 1745 key = _dbus_strdup (keys[i]); 1746 if (key == NULL) 1747 goto out; 1748 value = _dbus_strdup ("Value!"); 1749 if (value == NULL) 1750 goto out; 1751 1752 if (!_dbus_hash_iter_lookup (table1, 1753 key, TRUE, &iter)) 1754 goto out; 1755 _dbus_assert (_dbus_hash_iter_get_value (&iter) == NULL); 1756 _dbus_hash_iter_set_value (&iter, value); 1757 1758 value = _dbus_strdup (keys[i]); 1759 if (value == NULL) 1760 goto out; 1761 1762 if (!_dbus_hash_iter_lookup (table2, 1763 _DBUS_INT_TO_POINTER (i), TRUE, &iter)) 1764 goto out; 1765 _dbus_assert (_dbus_hash_iter_get_value (&iter) == NULL); 1766 _dbus_hash_iter_set_value (&iter, value); 1767 1768 _dbus_assert (count_entries (table1) == i + 1); 1769 _dbus_assert (count_entries (table2) == i + 1); 1770 1771 if (!_dbus_hash_iter_lookup (table1, keys[i], FALSE, &iter)) 1772 goto out; 1773 1774 value = _dbus_hash_iter_get_value (&iter); 1775 _dbus_assert (value != NULL); 1776 _dbus_assert (strcmp (value, "Value!") == 0); 1777 1778 /* Iterate just to be sure it works, though 1779 * it's a stupid thing to do 1780 */ 1781 while (_dbus_hash_iter_next (&iter)) 1782 ; 1783 1784 if (!_dbus_hash_iter_lookup (table2, _DBUS_INT_TO_POINTER (i), FALSE, &iter)) 1785 goto out; 1786 1787 value = _dbus_hash_iter_get_value (&iter); 1788 _dbus_assert (value != NULL); 1789 _dbus_assert (strcmp (value, keys[i]) == 0); 1790 1791 /* Iterate just to be sure it works, though 1792 * it's a stupid thing to do 1793 */ 1794 while (_dbus_hash_iter_next (&iter)) 1795 ; 1796 1797 ++i; 1798 } 1799 1800 --i; 1801 while (i >= 0) 1802 { 1803 if (!_dbus_hash_iter_lookup (table1, keys[i], FALSE, &iter)) 1804 _dbus_assert_not_reached ("hash entry should have existed"); 1805 _dbus_hash_iter_remove_entry (&iter); 1806 1807 if (!_dbus_hash_iter_lookup (table2, _DBUS_INT_TO_POINTER (i), FALSE, &iter)) 1808 _dbus_assert_not_reached ("hash entry should have existed"); 1809 _dbus_hash_iter_remove_entry (&iter); 1810 1811 _dbus_assert (count_entries (table1) == i); 1812 _dbus_assert (count_entries (table2) == i); 1813 1814 --i; 1815 } 1816 1817 _dbus_hash_table_unref (table1); 1818 _dbus_hash_table_unref (table2); 1819 1820 ret = TRUE; 1821 1822 out: 1823 for (i = 0; i < N_HASH_KEYS; i++) 1824 dbus_free (keys[i]); 1825 1826 dbus_free (keys); 1827 1828 return ret; 1829 } 1830 1831 #endif /* DBUS_BUILD_TESTS */ 1832