hashtable.c revision 35c4bbdf
135c4bbdfSmrg#ifdef HAVE_DIX_CONFIG_H 235c4bbdfSmrg#include <dix-config.h> 335c4bbdfSmrg#endif 435c4bbdfSmrg 535c4bbdfSmrg#include <stdlib.h> 635c4bbdfSmrg#include "misc.h" 735c4bbdfSmrg#include "hashtable.h" 835c4bbdfSmrg 935c4bbdfSmrg/* HashResourceID */ 1035c4bbdfSmrg#include "resource.h" 1135c4bbdfSmrg 1235c4bbdfSmrg#define INITHASHSIZE 6 1335c4bbdfSmrg#define MAXHASHSIZE 11 1435c4bbdfSmrg 1535c4bbdfSmrgstruct HashTableRec { 1635c4bbdfSmrg int keySize; 1735c4bbdfSmrg int dataSize; 1835c4bbdfSmrg 1935c4bbdfSmrg int elements; /* number of elements inserted */ 2035c4bbdfSmrg int bucketBits; /* number of buckets is 1 << bucketBits */ 2135c4bbdfSmrg struct xorg_list *buckets; /* array of bucket list heads */ 2235c4bbdfSmrg 2335c4bbdfSmrg HashFunc hash; 2435c4bbdfSmrg HashCompareFunc compare; 2535c4bbdfSmrg 2635c4bbdfSmrg void *cdata; 2735c4bbdfSmrg}; 2835c4bbdfSmrg 2935c4bbdfSmrgtypedef struct { 3035c4bbdfSmrg struct xorg_list l; 3135c4bbdfSmrg void *key; 3235c4bbdfSmrg void *data; 3335c4bbdfSmrg} BucketRec, *BucketPtr; 3435c4bbdfSmrg 3535c4bbdfSmrgHashTable 3635c4bbdfSmrght_create(int keySize, 3735c4bbdfSmrg int dataSize, 3835c4bbdfSmrg HashFunc hash, 3935c4bbdfSmrg HashCompareFunc compare, 4035c4bbdfSmrg void *cdata) 4135c4bbdfSmrg{ 4235c4bbdfSmrg int c; 4335c4bbdfSmrg int numBuckets; 4435c4bbdfSmrg HashTable ht = malloc(sizeof(struct HashTableRec)); 4535c4bbdfSmrg 4635c4bbdfSmrg if (!ht) { 4735c4bbdfSmrg return NULL; 4835c4bbdfSmrg } 4935c4bbdfSmrg 5035c4bbdfSmrg ht->keySize = keySize; 5135c4bbdfSmrg ht->dataSize = dataSize; 5235c4bbdfSmrg ht->hash = hash; 5335c4bbdfSmrg ht->compare = compare; 5435c4bbdfSmrg ht->elements = 0; 5535c4bbdfSmrg ht->bucketBits = INITHASHSIZE; 5635c4bbdfSmrg numBuckets = 1 << ht->bucketBits; 5735c4bbdfSmrg ht->buckets = xallocarray(numBuckets, sizeof(*ht->buckets)); 5835c4bbdfSmrg ht->cdata = cdata; 5935c4bbdfSmrg 6035c4bbdfSmrg if (ht->buckets) { 6135c4bbdfSmrg for (c = 0; c < numBuckets; ++c) { 6235c4bbdfSmrg xorg_list_init(&ht->buckets[c]); 6335c4bbdfSmrg } 6435c4bbdfSmrg return ht; 6535c4bbdfSmrg } else { 6635c4bbdfSmrg free(ht); 6735c4bbdfSmrg return NULL; 6835c4bbdfSmrg } 6935c4bbdfSmrg} 7035c4bbdfSmrg 7135c4bbdfSmrgvoid 7235c4bbdfSmrght_destroy(HashTable ht) 7335c4bbdfSmrg{ 7435c4bbdfSmrg int c; 7535c4bbdfSmrg BucketPtr it, tmp; 7635c4bbdfSmrg int numBuckets = 1 << ht->bucketBits; 7735c4bbdfSmrg for (c = 0; c < numBuckets; ++c) { 7835c4bbdfSmrg xorg_list_for_each_entry_safe(it, tmp, &ht->buckets[c], l) { 7935c4bbdfSmrg xorg_list_del(&it->l); 8035c4bbdfSmrg free(it); 8135c4bbdfSmrg } 8235c4bbdfSmrg } 8335c4bbdfSmrg free(ht->buckets); 8435c4bbdfSmrg} 8535c4bbdfSmrg 8635c4bbdfSmrgstatic Bool 8735c4bbdfSmrgdouble_size(HashTable ht) 8835c4bbdfSmrg{ 8935c4bbdfSmrg struct xorg_list *newBuckets; 9035c4bbdfSmrg int numBuckets = 1 << ht->bucketBits; 9135c4bbdfSmrg int newBucketBits = ht->bucketBits + 1; 9235c4bbdfSmrg int newNumBuckets = 1 << newBucketBits; 9335c4bbdfSmrg int c; 9435c4bbdfSmrg 9535c4bbdfSmrg newBuckets = xallocarray(newNumBuckets, sizeof(*ht->buckets)); 9635c4bbdfSmrg if (newBuckets) { 9735c4bbdfSmrg for (c = 0; c < newNumBuckets; ++c) { 9835c4bbdfSmrg xorg_list_init(&newBuckets[c]); 9935c4bbdfSmrg } 10035c4bbdfSmrg 10135c4bbdfSmrg for (c = 0; c < numBuckets; ++c) { 10235c4bbdfSmrg BucketPtr it, tmp; 10335c4bbdfSmrg xorg_list_for_each_entry_safe(it, tmp, &ht->buckets[c], l) { 10435c4bbdfSmrg struct xorg_list *newBucket = 10535c4bbdfSmrg &newBuckets[ht->hash(ht->cdata, it->key, newBucketBits)]; 10635c4bbdfSmrg xorg_list_del(&it->l); 10735c4bbdfSmrg xorg_list_add(&it->l, newBucket); 10835c4bbdfSmrg } 10935c4bbdfSmrg } 11035c4bbdfSmrg free(ht->buckets); 11135c4bbdfSmrg 11235c4bbdfSmrg ht->buckets = newBuckets; 11335c4bbdfSmrg ht->bucketBits = newBucketBits; 11435c4bbdfSmrg return TRUE; 11535c4bbdfSmrg } else { 11635c4bbdfSmrg return FALSE; 11735c4bbdfSmrg } 11835c4bbdfSmrg} 11935c4bbdfSmrg 12035c4bbdfSmrgvoid * 12135c4bbdfSmrght_add(HashTable ht, const void *key) 12235c4bbdfSmrg{ 12335c4bbdfSmrg unsigned index = ht->hash(ht->cdata, key, ht->bucketBits); 12435c4bbdfSmrg struct xorg_list *bucket = &ht->buckets[index]; 12535c4bbdfSmrg BucketRec *elem = calloc(1, sizeof(BucketRec)); 12635c4bbdfSmrg if (!elem) { 12735c4bbdfSmrg goto outOfMemory; 12835c4bbdfSmrg } 12935c4bbdfSmrg elem->key = malloc(ht->keySize); 13035c4bbdfSmrg if (!elem->key) { 13135c4bbdfSmrg goto outOfMemory; 13235c4bbdfSmrg } 13335c4bbdfSmrg /* we avoid signaling an out-of-memory error if dataSize is 0 */ 13435c4bbdfSmrg elem->data = calloc(1, ht->dataSize); 13535c4bbdfSmrg if (ht->dataSize && !elem->data) { 13635c4bbdfSmrg goto outOfMemory; 13735c4bbdfSmrg } 13835c4bbdfSmrg xorg_list_add(&elem->l, bucket); 13935c4bbdfSmrg ++ht->elements; 14035c4bbdfSmrg 14135c4bbdfSmrg memcpy(elem->key, key, ht->keySize); 14235c4bbdfSmrg 14335c4bbdfSmrg if (ht->elements > 4 * (1 << ht->bucketBits) && 14435c4bbdfSmrg ht->bucketBits < MAXHASHSIZE) { 14535c4bbdfSmrg if (!double_size(ht)) { 14635c4bbdfSmrg --ht->elements; 14735c4bbdfSmrg xorg_list_del(&elem->l); 14835c4bbdfSmrg goto outOfMemory; 14935c4bbdfSmrg } 15035c4bbdfSmrg } 15135c4bbdfSmrg 15235c4bbdfSmrg /* if memory allocation has failed due to dataSize being 0, return 15335c4bbdfSmrg a "dummy" pointer pointing at the of the key */ 15435c4bbdfSmrg return elem->data ? elem->data : ((char*) elem->key + ht->keySize); 15535c4bbdfSmrg 15635c4bbdfSmrg outOfMemory: 15735c4bbdfSmrg if (elem) { 15835c4bbdfSmrg free(elem->key); 15935c4bbdfSmrg free(elem->data); 16035c4bbdfSmrg free(elem); 16135c4bbdfSmrg } 16235c4bbdfSmrg 16335c4bbdfSmrg return NULL; 16435c4bbdfSmrg} 16535c4bbdfSmrg 16635c4bbdfSmrgvoid 16735c4bbdfSmrght_remove(HashTable ht, const void *key) 16835c4bbdfSmrg{ 16935c4bbdfSmrg unsigned index = ht->hash(ht->cdata, key, ht->bucketBits); 17035c4bbdfSmrg struct xorg_list *bucket = &ht->buckets[index]; 17135c4bbdfSmrg BucketPtr it; 17235c4bbdfSmrg 17335c4bbdfSmrg xorg_list_for_each_entry(it, bucket, l) { 17435c4bbdfSmrg if (ht->compare(ht->cdata, key, it->key) == 0) { 17535c4bbdfSmrg xorg_list_del(&it->l); 17635c4bbdfSmrg --ht->elements; 17735c4bbdfSmrg free(it->key); 17835c4bbdfSmrg free(it->data); 17935c4bbdfSmrg free(it); 18035c4bbdfSmrg return; 18135c4bbdfSmrg } 18235c4bbdfSmrg } 18335c4bbdfSmrg} 18435c4bbdfSmrg 18535c4bbdfSmrgvoid * 18635c4bbdfSmrght_find(HashTable ht, const void *key) 18735c4bbdfSmrg{ 18835c4bbdfSmrg unsigned index = ht->hash(ht->cdata, key, ht->bucketBits); 18935c4bbdfSmrg struct xorg_list *bucket = &ht->buckets[index]; 19035c4bbdfSmrg BucketPtr it; 19135c4bbdfSmrg 19235c4bbdfSmrg xorg_list_for_each_entry(it, bucket, l) { 19335c4bbdfSmrg if (ht->compare(ht->cdata, key, it->key) == 0) { 19435c4bbdfSmrg return it->data ? it->data : ((char*) it->key + ht->keySize); 19535c4bbdfSmrg } 19635c4bbdfSmrg } 19735c4bbdfSmrg 19835c4bbdfSmrg return NULL; 19935c4bbdfSmrg} 20035c4bbdfSmrg 20135c4bbdfSmrgvoid 20235c4bbdfSmrght_dump_distribution(HashTable ht) 20335c4bbdfSmrg{ 20435c4bbdfSmrg int c; 20535c4bbdfSmrg int numBuckets = 1 << ht->bucketBits; 20635c4bbdfSmrg for (c = 0; c < numBuckets; ++c) { 20735c4bbdfSmrg BucketPtr it; 20835c4bbdfSmrg int n = 0; 20935c4bbdfSmrg 21035c4bbdfSmrg xorg_list_for_each_entry(it, &ht->buckets[c], l) { 21135c4bbdfSmrg ++n; 21235c4bbdfSmrg } 21335c4bbdfSmrg printf("%d: %d\n", c, n); 21435c4bbdfSmrg } 21535c4bbdfSmrg} 21635c4bbdfSmrg 21735c4bbdfSmrg/* Picked the function from http://burtleburtle.net/bob/hash/doobs.html by 21835c4bbdfSmrg Bob Jenkins, which is released in public domain */ 21935c4bbdfSmrgstatic CARD32 22035c4bbdfSmrgone_at_a_time_hash(const void *data, int len) 22135c4bbdfSmrg{ 22235c4bbdfSmrg CARD32 hash; 22335c4bbdfSmrg int i; 22435c4bbdfSmrg const char *key = data; 22535c4bbdfSmrg for (hash=0, i=0; i<len; ++i) { 22635c4bbdfSmrg hash += key[i]; 22735c4bbdfSmrg hash += (hash << 10); 22835c4bbdfSmrg hash ^= (hash >> 6); 22935c4bbdfSmrg } 23035c4bbdfSmrg hash += (hash << 3); 23135c4bbdfSmrg hash ^= (hash >> 11); 23235c4bbdfSmrg hash += (hash << 15); 23335c4bbdfSmrg return hash; 23435c4bbdfSmrg} 23535c4bbdfSmrg 23635c4bbdfSmrgunsigned 23735c4bbdfSmrght_generic_hash(void *cdata, const void *ptr, int numBits) 23835c4bbdfSmrg{ 23935c4bbdfSmrg HtGenericHashSetupPtr setup = cdata; 24035c4bbdfSmrg return one_at_a_time_hash(ptr, setup->keySize) & ~((~0) << numBits); 24135c4bbdfSmrg} 24235c4bbdfSmrg 24335c4bbdfSmrgint 24435c4bbdfSmrght_generic_compare(void *cdata, const void *l, const void *r) 24535c4bbdfSmrg{ 24635c4bbdfSmrg HtGenericHashSetupPtr setup = cdata; 24735c4bbdfSmrg return memcmp(l, r, setup->keySize); 24835c4bbdfSmrg} 24935c4bbdfSmrg 25035c4bbdfSmrgunsigned 25135c4bbdfSmrght_resourceid_hash(void * cdata, const void * data, int numBits) 25235c4bbdfSmrg{ 25335c4bbdfSmrg const XID* idPtr = data; 25435c4bbdfSmrg XID id = *idPtr & RESOURCE_ID_MASK; 25535c4bbdfSmrg (void) cdata; 25635c4bbdfSmrg return HashResourceID(id, numBits); 25735c4bbdfSmrg} 25835c4bbdfSmrg 25935c4bbdfSmrgint 26035c4bbdfSmrght_resourceid_compare(void* cdata, const void* a, const void* b) 26135c4bbdfSmrg{ 26235c4bbdfSmrg const XID* xa = a; 26335c4bbdfSmrg const XID* xb = b; 26435c4bbdfSmrg (void) cdata; 26535c4bbdfSmrg return 26635c4bbdfSmrg *xa < *xb ? -1 : 26735c4bbdfSmrg *xa > *xb ? 1 : 26835c4bbdfSmrg 0; 26935c4bbdfSmrg} 27035c4bbdfSmrg 27135c4bbdfSmrgvoid 27235c4bbdfSmrght_dump_contents(HashTable ht, 27335c4bbdfSmrg void (*print_key)(void *opaque, void *key), 27435c4bbdfSmrg void (*print_value)(void *opaque, void *value), 27535c4bbdfSmrg void* opaque) 27635c4bbdfSmrg{ 27735c4bbdfSmrg int c; 27835c4bbdfSmrg int numBuckets = 1 << ht->bucketBits; 27935c4bbdfSmrg for (c = 0; c < numBuckets; ++c) { 28035c4bbdfSmrg BucketPtr it; 28135c4bbdfSmrg int n = 0; 28235c4bbdfSmrg 28335c4bbdfSmrg printf("%d: ", c); 28435c4bbdfSmrg xorg_list_for_each_entry(it, &ht->buckets[c], l) { 28535c4bbdfSmrg if (n > 0) { 28635c4bbdfSmrg printf(", "); 28735c4bbdfSmrg } 28835c4bbdfSmrg print_key(opaque, it->key); 28935c4bbdfSmrg printf("->"); 29035c4bbdfSmrg print_value(opaque, it->data); 29135c4bbdfSmrg ++n; 29235c4bbdfSmrg } 29335c4bbdfSmrg printf("\n"); 29435c4bbdfSmrg } 29535c4bbdfSmrg} 296