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); 801b5d61b8Smrg free(it->key); 811b5d61b8Smrg free(it->data); 8235c4bbdfSmrg free(it); 8335c4bbdfSmrg } 8435c4bbdfSmrg } 8535c4bbdfSmrg free(ht->buckets); 861b5d61b8Smrg free(ht); 8735c4bbdfSmrg} 8835c4bbdfSmrg 8935c4bbdfSmrgstatic Bool 9035c4bbdfSmrgdouble_size(HashTable ht) 9135c4bbdfSmrg{ 9235c4bbdfSmrg struct xorg_list *newBuckets; 9335c4bbdfSmrg int numBuckets = 1 << ht->bucketBits; 9435c4bbdfSmrg int newBucketBits = ht->bucketBits + 1; 9535c4bbdfSmrg int newNumBuckets = 1 << newBucketBits; 9635c4bbdfSmrg int c; 9735c4bbdfSmrg 9835c4bbdfSmrg newBuckets = xallocarray(newNumBuckets, sizeof(*ht->buckets)); 9935c4bbdfSmrg if (newBuckets) { 10035c4bbdfSmrg for (c = 0; c < newNumBuckets; ++c) { 10135c4bbdfSmrg xorg_list_init(&newBuckets[c]); 10235c4bbdfSmrg } 10335c4bbdfSmrg 10435c4bbdfSmrg for (c = 0; c < numBuckets; ++c) { 10535c4bbdfSmrg BucketPtr it, tmp; 10635c4bbdfSmrg xorg_list_for_each_entry_safe(it, tmp, &ht->buckets[c], l) { 10735c4bbdfSmrg struct xorg_list *newBucket = 10835c4bbdfSmrg &newBuckets[ht->hash(ht->cdata, it->key, newBucketBits)]; 10935c4bbdfSmrg xorg_list_del(&it->l); 11035c4bbdfSmrg xorg_list_add(&it->l, newBucket); 11135c4bbdfSmrg } 11235c4bbdfSmrg } 11335c4bbdfSmrg free(ht->buckets); 11435c4bbdfSmrg 11535c4bbdfSmrg ht->buckets = newBuckets; 11635c4bbdfSmrg ht->bucketBits = newBucketBits; 11735c4bbdfSmrg return TRUE; 11835c4bbdfSmrg } else { 11935c4bbdfSmrg return FALSE; 12035c4bbdfSmrg } 12135c4bbdfSmrg} 12235c4bbdfSmrg 12335c4bbdfSmrgvoid * 12435c4bbdfSmrght_add(HashTable ht, const void *key) 12535c4bbdfSmrg{ 12635c4bbdfSmrg unsigned index = ht->hash(ht->cdata, key, ht->bucketBits); 12735c4bbdfSmrg struct xorg_list *bucket = &ht->buckets[index]; 12835c4bbdfSmrg BucketRec *elem = calloc(1, sizeof(BucketRec)); 12935c4bbdfSmrg if (!elem) { 13035c4bbdfSmrg goto outOfMemory; 13135c4bbdfSmrg } 13235c4bbdfSmrg elem->key = malloc(ht->keySize); 13335c4bbdfSmrg if (!elem->key) { 13435c4bbdfSmrg goto outOfMemory; 13535c4bbdfSmrg } 13635c4bbdfSmrg /* we avoid signaling an out-of-memory error if dataSize is 0 */ 13735c4bbdfSmrg elem->data = calloc(1, ht->dataSize); 13835c4bbdfSmrg if (ht->dataSize && !elem->data) { 13935c4bbdfSmrg goto outOfMemory; 14035c4bbdfSmrg } 14135c4bbdfSmrg xorg_list_add(&elem->l, bucket); 14235c4bbdfSmrg ++ht->elements; 14335c4bbdfSmrg 14435c4bbdfSmrg memcpy(elem->key, key, ht->keySize); 14535c4bbdfSmrg 14635c4bbdfSmrg if (ht->elements > 4 * (1 << ht->bucketBits) && 14735c4bbdfSmrg ht->bucketBits < MAXHASHSIZE) { 14835c4bbdfSmrg if (!double_size(ht)) { 14935c4bbdfSmrg --ht->elements; 15035c4bbdfSmrg xorg_list_del(&elem->l); 15135c4bbdfSmrg goto outOfMemory; 15235c4bbdfSmrg } 15335c4bbdfSmrg } 15435c4bbdfSmrg 15535c4bbdfSmrg /* if memory allocation has failed due to dataSize being 0, return 15635c4bbdfSmrg a "dummy" pointer pointing at the of the key */ 15735c4bbdfSmrg return elem->data ? elem->data : ((char*) elem->key + ht->keySize); 15835c4bbdfSmrg 15935c4bbdfSmrg outOfMemory: 16035c4bbdfSmrg if (elem) { 16135c4bbdfSmrg free(elem->key); 16235c4bbdfSmrg free(elem->data); 16335c4bbdfSmrg free(elem); 16435c4bbdfSmrg } 16535c4bbdfSmrg 16635c4bbdfSmrg return NULL; 16735c4bbdfSmrg} 16835c4bbdfSmrg 16935c4bbdfSmrgvoid 17035c4bbdfSmrght_remove(HashTable ht, const void *key) 17135c4bbdfSmrg{ 17235c4bbdfSmrg unsigned index = ht->hash(ht->cdata, key, ht->bucketBits); 17335c4bbdfSmrg struct xorg_list *bucket = &ht->buckets[index]; 17435c4bbdfSmrg BucketPtr it; 17535c4bbdfSmrg 17635c4bbdfSmrg xorg_list_for_each_entry(it, bucket, l) { 17735c4bbdfSmrg if (ht->compare(ht->cdata, key, it->key) == 0) { 17835c4bbdfSmrg xorg_list_del(&it->l); 17935c4bbdfSmrg --ht->elements; 18035c4bbdfSmrg free(it->key); 18135c4bbdfSmrg free(it->data); 18235c4bbdfSmrg free(it); 18335c4bbdfSmrg return; 18435c4bbdfSmrg } 18535c4bbdfSmrg } 18635c4bbdfSmrg} 18735c4bbdfSmrg 18835c4bbdfSmrgvoid * 18935c4bbdfSmrght_find(HashTable ht, const void *key) 19035c4bbdfSmrg{ 19135c4bbdfSmrg unsigned index = ht->hash(ht->cdata, key, ht->bucketBits); 19235c4bbdfSmrg struct xorg_list *bucket = &ht->buckets[index]; 19335c4bbdfSmrg BucketPtr it; 19435c4bbdfSmrg 19535c4bbdfSmrg xorg_list_for_each_entry(it, bucket, l) { 19635c4bbdfSmrg if (ht->compare(ht->cdata, key, it->key) == 0) { 19735c4bbdfSmrg return it->data ? it->data : ((char*) it->key + ht->keySize); 19835c4bbdfSmrg } 19935c4bbdfSmrg } 20035c4bbdfSmrg 20135c4bbdfSmrg return NULL; 20235c4bbdfSmrg} 20335c4bbdfSmrg 20435c4bbdfSmrgvoid 20535c4bbdfSmrght_dump_distribution(HashTable ht) 20635c4bbdfSmrg{ 20735c4bbdfSmrg int c; 20835c4bbdfSmrg int numBuckets = 1 << ht->bucketBits; 20935c4bbdfSmrg for (c = 0; c < numBuckets; ++c) { 21035c4bbdfSmrg BucketPtr it; 21135c4bbdfSmrg int n = 0; 21235c4bbdfSmrg 21335c4bbdfSmrg xorg_list_for_each_entry(it, &ht->buckets[c], l) { 21435c4bbdfSmrg ++n; 21535c4bbdfSmrg } 21635c4bbdfSmrg printf("%d: %d\n", c, n); 21735c4bbdfSmrg } 21835c4bbdfSmrg} 21935c4bbdfSmrg 22035c4bbdfSmrg/* Picked the function from http://burtleburtle.net/bob/hash/doobs.html by 22135c4bbdfSmrg Bob Jenkins, which is released in public domain */ 22235c4bbdfSmrgstatic CARD32 22335c4bbdfSmrgone_at_a_time_hash(const void *data, int len) 22435c4bbdfSmrg{ 22535c4bbdfSmrg CARD32 hash; 22635c4bbdfSmrg int i; 22735c4bbdfSmrg const char *key = data; 22835c4bbdfSmrg for (hash=0, i=0; i<len; ++i) { 22935c4bbdfSmrg hash += key[i]; 23035c4bbdfSmrg hash += (hash << 10); 23135c4bbdfSmrg hash ^= (hash >> 6); 23235c4bbdfSmrg } 23335c4bbdfSmrg hash += (hash << 3); 23435c4bbdfSmrg hash ^= (hash >> 11); 23535c4bbdfSmrg hash += (hash << 15); 23635c4bbdfSmrg return hash; 23735c4bbdfSmrg} 23835c4bbdfSmrg 23935c4bbdfSmrgunsigned 24035c4bbdfSmrght_generic_hash(void *cdata, const void *ptr, int numBits) 24135c4bbdfSmrg{ 24235c4bbdfSmrg HtGenericHashSetupPtr setup = cdata; 243ed6184dfSmrg return one_at_a_time_hash(ptr, setup->keySize) & ~((~0U) << numBits); 24435c4bbdfSmrg} 24535c4bbdfSmrg 24635c4bbdfSmrgint 24735c4bbdfSmrght_generic_compare(void *cdata, const void *l, const void *r) 24835c4bbdfSmrg{ 24935c4bbdfSmrg HtGenericHashSetupPtr setup = cdata; 25035c4bbdfSmrg return memcmp(l, r, setup->keySize); 25135c4bbdfSmrg} 25235c4bbdfSmrg 25335c4bbdfSmrgunsigned 25435c4bbdfSmrght_resourceid_hash(void * cdata, const void * data, int numBits) 25535c4bbdfSmrg{ 25635c4bbdfSmrg const XID* idPtr = data; 25735c4bbdfSmrg XID id = *idPtr & RESOURCE_ID_MASK; 25835c4bbdfSmrg (void) cdata; 25935c4bbdfSmrg return HashResourceID(id, numBits); 26035c4bbdfSmrg} 26135c4bbdfSmrg 26235c4bbdfSmrgint 26335c4bbdfSmrght_resourceid_compare(void* cdata, const void* a, const void* b) 26435c4bbdfSmrg{ 26535c4bbdfSmrg const XID* xa = a; 26635c4bbdfSmrg const XID* xb = b; 26735c4bbdfSmrg (void) cdata; 26835c4bbdfSmrg return 26935c4bbdfSmrg *xa < *xb ? -1 : 27035c4bbdfSmrg *xa > *xb ? 1 : 27135c4bbdfSmrg 0; 27235c4bbdfSmrg} 27335c4bbdfSmrg 27435c4bbdfSmrgvoid 27535c4bbdfSmrght_dump_contents(HashTable ht, 27635c4bbdfSmrg void (*print_key)(void *opaque, void *key), 27735c4bbdfSmrg void (*print_value)(void *opaque, void *value), 27835c4bbdfSmrg void* opaque) 27935c4bbdfSmrg{ 28035c4bbdfSmrg int c; 28135c4bbdfSmrg int numBuckets = 1 << ht->bucketBits; 28235c4bbdfSmrg for (c = 0; c < numBuckets; ++c) { 28335c4bbdfSmrg BucketPtr it; 28435c4bbdfSmrg int n = 0; 28535c4bbdfSmrg 28635c4bbdfSmrg printf("%d: ", c); 28735c4bbdfSmrg xorg_list_for_each_entry(it, &ht->buckets[c], l) { 28835c4bbdfSmrg if (n > 0) { 28935c4bbdfSmrg printf(", "); 29035c4bbdfSmrg } 29135c4bbdfSmrg print_key(opaque, it->key); 29235c4bbdfSmrg printf("->"); 29335c4bbdfSmrg print_value(opaque, it->data); 29435c4bbdfSmrg ++n; 29535c4bbdfSmrg } 29635c4bbdfSmrg printf("\n"); 29735c4bbdfSmrg } 29835c4bbdfSmrg} 299