hash_table.c
来自「xen虚拟机源代码安装包」· C语言 代码 · 共 659 行 · 第 1/2 页
C
659 行
* * @param z entry to free */inline void HTEntry_free(HTEntry *z){ if(z){ deallocate(z); }}/** Free an entry in a hashtable. * The table's entry_free_fn is used is defined, otherwise * the HTEntry itself is freed. * * @param table hashtable * @param entry to free */inline void HashTable_free_entry(HashTable *table, HTEntry *entry){ if(!entry) return; if(table && table->entry_free_fn){ table->entry_free_fn(table, entry); } else { HTEntry_free(entry); }}/** Get the first entry satisfying a test from the bucket for the * given hashcode. * * @param table to look in * @param hashcode indicates the bucket * @param test_fn test to apply to elements * @param arg first argument to calls to test_fn * @return entry found, or 0 */inline HTEntry * HashTable_find_entry(HashTable *table, Hashcode hashcode, TableTestFn *test_fn, TableArg arg){ HTBucket *bucket; HTEntry *entry = NULL; HTEntry *next; bucket = get_bucket(table, hashcode); for(entry = bucket->head; entry; entry = next){ next = entry->next; if(test_fn(arg, table, entry)){ break; } } return entry;}/** Test hashtable keys for equality. * Uses the table's key_equal_fn if defined, otherwise pointer equality. * * @param key1 key to compare * @param key2 key to compare * @return 1 if equal, 0 otherwise */inline int HashTable_key_equal(HashTable *table, void *key1, void *key2){ if(table->key_size){ return memcmp(key1, key2, table->key_size) == 0; } return (table->key_equal_fn ? table->key_equal_fn(key1, key2) : key1 == key2);}/** Compute the hashcode of a hashtable key. * The table's key_hash_fn is used if defined, otherwise the address of * the key is hashed. * * @param table hashtable * @param key to hash * @return hashcode */inline Hashcode HashTable_key_hash(HashTable *table, void *key){ if(table->key_size){ return _hash(key, table->key_size, 0); } return (table->key_hash_fn ? table->key_hash_fn(key) : hash_hvoid(0, &key, sizeof(key)));}/** Test if an entry has a given key. * * @param arg containing key to test for * @param table the entry is in * @param entry to test * @return 1 if the entry has the key, 0 otherwise */static inline int has_key(TableArg arg, HashTable *table, HTEntry *entry){ return HashTable_key_equal(table, arg.ptr, entry->key);}/** Get an entry with a given key. * * @param table to search * @param key to look for * @return entry if found, null otherwise */inline HTEntry * HashTable_get_entry(HashTable *table, void *key){ Hashcode hashcode; HTBucket *bucket; HTEntry *entry = NULL; HTEntry *next; hashcode = HashTable_key_hash(table, key); bucket = get_bucket(table, hashcode); for(entry = bucket->head; entry; entry = next){ next = entry->next; if(HashTable_key_equal(table, key, entry->key)){ break; } } return entry;}/** Get the value of an entry with a given key. * * @param table to search * @param key to look for * @return value if an entry was found, null otherwise */inline void * HashTable_get(HashTable *table, void *key){ HTEntry *entry = HashTable_get_entry(table, key); return (entry ? entry->value : 0);}/** Print the buckets in a table. * * @param table to print */void show_buckets(HashTable *table, IOStream *io){ int i,j ; IOStream_print(io, "entry_count=%d buckets_n=%d\n", table->entry_count, table->buckets_n); for(i=0; i < table->buckets_n; i++){ if(0 || table->buckets[i].count>0){ IOStream_print(io, "bucket %3d %3d %10p ", i, table->buckets[i].count, table->buckets[i].head); for(j = table->buckets[i].count; j>0; j--){ IOStream_print(io, "+"); } IOStream_print(io, "\n"); } } HashTable_print(table, io); } /** Print an entry in a table. * * @param entry to print * @param arg a pointer to an IOStream to print to * @return 0 */static int print_entry(TableArg arg, HashTable *table, HTEntry *entry){ IOStream *io = (IOStream*)arg.ptr; IOStream_print(io, " b=%4lx h=%08lx |-> e=%8p k=%8p v=%8p\n", entry->hashcode % table->buckets_n, entry->hashcode, entry, entry->key, entry->value); return 0;}/** Print a hash table. * * @param table to print */void HashTable_print(HashTable *table, IOStream *io){ IOStream_print(io, "{\n"); HashTable_map(table, print_entry, (TableArg){ ptr: io }); IOStream_print(io, "}\n");}/*==========================================================================*//** Add an entry to the bucket for the * given hashcode. * * @param table to insert in * @param hashcode indicates the bucket * @param key to add an entry for * @param value to add an entry for * @return entry on success, 0 on failure */inline HTEntry * HashTable_add_entry(HashTable *table, Hashcode hashcode, void *key, void *value){ HTEntry *entry = HTEntry_new(hashcode, key, value); if(entry){ push_on_bucket(table, hashcode, entry); table->entry_count++; } return entry;}/** Move the front entry for a bucket to the correct point in the bucket order as * defined by the order function. If this is called every time a new entry is added * the bucket will be maintained in sorted order. * * @param table to modify * @param hashcode indicates the bucket * @param order entry comparison function * @return 0 if an entry was moved, 1 if not */int HashTable_order_bucket(HashTable *table, Hashcode hashcode, TableOrderFn *order){ HTEntry *new_entry = NULL, *prev = NULL, *entry = NULL; HTBucket *bucket; int err = 1; bucket = get_bucket(table, hashcode); new_entry = bucket->head; if(!new_entry || !new_entry->next) goto exit; for(entry = new_entry->next; entry; prev = entry, entry = entry->next){ if(order(new_entry, entry) <= 0) break; } if(prev){ err = 0; bucket->head = new_entry->next; new_entry->next = entry; prev->next = new_entry; } exit: return err;}/** Add an entry to a hashtable. * The entry is added to the bucket for its key's hashcode. * * @param table to insert in * @param key to add an entry for * @param value to add an entry for * @return entry on success, 0 on failure */inline HTEntry * HashTable_add(HashTable *table, void *key, void *value){ return HashTable_add_entry(table, HashTable_key_hash(table, key), key, value);}/** Remove entries satisfying a test from the bucket for the * given hashcode. * * @param table to remove from * @param hashcode indicates the bucket * @param test_fn test to apply to elements * @param arg first argument to calls to test_fn * @return number of entries removed */inline int HashTable_remove_entry(HashTable *table, Hashcode hashcode, TableTestFn *test_fn, TableArg arg){ HTBucket *bucket; HTEntry *entry, *prev = NULL, *next; int removed_count = 0; bucket = get_bucket(table, hashcode); for(entry = bucket->head; entry; entry = next){ next = entry->next; if(test_fn(arg, table, entry)){ if(prev){ prev->next = next; } else { bucket->head = next; } bucket->count--; table->entry_count--; removed_count++; HashTable_free_entry(table, entry); entry = NULL; } prev = entry; } return removed_count;}/** Remove entries with a given key. * * @param table to remove from * @param key of entries to remove * @return number of entries removed */inline int HashTable_remove(HashTable *table, void *key){ Hashcode hashcode; HTBucket *bucket; HTEntry *entry, *prev = NULL, *next; int removed_count = 0; hashcode = HashTable_key_hash(table, key); bucket = get_bucket(table, hashcode); for(entry = bucket->head; entry; entry = next){ next = entry->next; if(HashTable_key_equal(table, key, entry->key)){ if(prev){ prev->next = next; } else { bucket->head = next; } bucket->count--; table->entry_count--; removed_count++; HashTable_free_entry(table, entry); entry = NULL; } prev = entry; } return removed_count;}/** Remove (and free) all the entries in a bucket. * * @param bucket to clear */static inline void bucket_clear(HashTable *table, HTBucket *bucket){ HTEntry *entry, *next; for(entry = bucket->head; entry; entry = next){ next = entry->next; HashTable_free_entry(table, entry); } bucket->head = NULL; table->entry_count -= bucket->count; bucket->count = 0;}/** Remove (and free) all the entries in a table. * * @param table to clear */void HashTable_clear(HashTable *table){ int i, n = table->buckets_n; for(i = 0; i < n; i++){ bucket_clear(table, table->buckets + i); }}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?