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