Edit

IABSD.fr/xenocara/xserver/Xext/hashtable.c

Branch :

  • Show log

    Commit

  • Author : matthieu
    Date : 2021-11-11 09:03:02
    Hash : e086cf5a
    Message : Update to xserver 21.1.0

  • xserver/Xext/hashtable.c
  • #ifdef HAVE_DIX_CONFIG_H
    #include <dix-config.h>
    #endif
    
    #include <stdlib.h>
    #include "misc.h"
    #include "hashtable.h"
    
    /* HashResourceID */
    #include "resource.h"
    
    #define INITHASHSIZE 6
    #define MAXHASHSIZE 11
    
    struct HashTableRec {
        int             keySize;
        int             dataSize;
    
        int             elements;   /* number of elements inserted */
        int             bucketBits; /* number of buckets is 1 << bucketBits */
        struct xorg_list *buckets;  /* array of bucket list heads */
    
        HashFunc        hash;
        HashCompareFunc compare;
    
        void            *cdata;
    };
    
    typedef struct {
        struct xorg_list l;
        void *key;
        void *data;
    } BucketRec, *BucketPtr;
    
    HashTable
    ht_create(int             keySize,
              int             dataSize,
              HashFunc        hash,
              HashCompareFunc compare,
              void            *cdata)
    {
        int c;
        int numBuckets;
        HashTable ht = malloc(sizeof(struct HashTableRec));
    
        if (!ht) {
            return NULL;
        }
    
        ht->keySize = keySize;
        ht->dataSize = dataSize;
        ht->hash = hash;
        ht->compare = compare;
        ht->elements = 0;
        ht->bucketBits = INITHASHSIZE;
        numBuckets = 1 << ht->bucketBits;
        ht->buckets = xallocarray(numBuckets, sizeof(*ht->buckets));
        ht->cdata = cdata;
    
        if (ht->buckets) {
            for (c = 0; c < numBuckets; ++c) {
                xorg_list_init(&ht->buckets[c]);
            }
            return ht;
        } else {
            free(ht);
            return NULL;
        }
    }
    
    void
    ht_destroy(HashTable ht)
    {
        int c;
        BucketPtr it, tmp;
        int numBuckets = 1 << ht->bucketBits;
        for (c = 0; c < numBuckets; ++c) {
            xorg_list_for_each_entry_safe(it, tmp, &ht->buckets[c], l) {
                xorg_list_del(&it->l);
                free(it->key);
                free(it->data);
                free(it);
            }
        }
        free(ht->buckets);
        free(ht);
    }
    
    static Bool
    double_size(HashTable ht)
    {
        struct xorg_list *newBuckets;
        int numBuckets = 1 << ht->bucketBits;
        int newBucketBits = ht->bucketBits + 1;
        int newNumBuckets = 1 << newBucketBits;
        int c;
    
        newBuckets = xallocarray(newNumBuckets, sizeof(*ht->buckets));
        if (newBuckets) {
            for (c = 0; c < newNumBuckets; ++c) {
                xorg_list_init(&newBuckets[c]);
            }
    
            for (c = 0; c < numBuckets; ++c) {
                BucketPtr it, tmp;
                xorg_list_for_each_entry_safe(it, tmp, &ht->buckets[c], l) {
                    struct xorg_list *newBucket =
                        &newBuckets[ht->hash(ht->cdata, it->key, newBucketBits)];
                    xorg_list_del(&it->l);
                    xorg_list_add(&it->l, newBucket);
                }
            }
            free(ht->buckets);
    
            ht->buckets = newBuckets;
            ht->bucketBits = newBucketBits;
            return TRUE;
        } else {
            return FALSE;
        }
    }
    
    void *
    ht_add(HashTable ht, const void *key)
    {
        unsigned index = ht->hash(ht->cdata, key, ht->bucketBits);
        struct xorg_list *bucket = &ht->buckets[index];
        BucketRec *elem = calloc(1, sizeof(BucketRec));
        if (!elem) {
            goto outOfMemory;
        }
        elem->key = malloc(ht->keySize);
        if (!elem->key) {
            goto outOfMemory;
        }
        /* we avoid signaling an out-of-memory error if dataSize is 0 */
        elem->data = calloc(1, ht->dataSize);
        if (ht->dataSize && !elem->data) {
            goto outOfMemory;
        }
        xorg_list_add(&elem->l, bucket);
        ++ht->elements;
    
        memcpy(elem->key, key, ht->keySize);
    
        if (ht->elements > 4 * (1 << ht->bucketBits) &&
            ht->bucketBits < MAXHASHSIZE) {
            if (!double_size(ht)) {
                --ht->elements;
                xorg_list_del(&elem->l);
                goto outOfMemory;
            }
        }
    
        /* if memory allocation has failed due to dataSize being 0, return
           a "dummy" pointer pointing at the of the key */
        return elem->data ? elem->data : ((char*) elem->key + ht->keySize);
    
     outOfMemory:
        if (elem) {
            free(elem->key);
            free(elem->data);
            free(elem);
        }
    
        return NULL;
    }
    
    void
    ht_remove(HashTable ht, const void *key)
    {
        unsigned index = ht->hash(ht->cdata, key, ht->bucketBits);
        struct xorg_list *bucket = &ht->buckets[index];
        BucketPtr it;
    
        xorg_list_for_each_entry(it, bucket, l) {
            if (ht->compare(ht->cdata, key, it->key) == 0) {
                xorg_list_del(&it->l);
                --ht->elements;
                free(it->key);
                free(it->data);
                free(it);
                return;
            }
        }
    }
    
    void *
    ht_find(HashTable ht, const void *key)
    {
        unsigned index = ht->hash(ht->cdata, key, ht->bucketBits);
        struct xorg_list *bucket = &ht->buckets[index];
        BucketPtr it;
    
        xorg_list_for_each_entry(it, bucket, l) {
            if (ht->compare(ht->cdata, key, it->key) == 0) {
                return it->data ? it->data : ((char*) it->key + ht->keySize);
            }
        }
    
        return NULL;
    }
    
    void
    ht_dump_distribution(HashTable ht)
    {
        int c;
        int numBuckets = 1 << ht->bucketBits;
        for (c = 0; c < numBuckets; ++c) {
            BucketPtr it;
            int n = 0;
    
            xorg_list_for_each_entry(it, &ht->buckets[c], l) {
                ++n;
            }
            printf("%d: %d\n", c, n);
        }
    }
    
    /* Picked the function from http://burtleburtle.net/bob/hash/doobs.html by
       Bob Jenkins, which is released in public domain */
    static CARD32
    one_at_a_time_hash(const void *data, int len)
    {
        CARD32 hash;
        int i;
        const char *key = data;
        for (hash=0, i=0; i<len; ++i) {
            hash += key[i];
            hash += (hash << 10);
            hash ^= (hash >> 6);
        }
        hash += (hash << 3);
        hash ^= (hash >> 11);
        hash += (hash << 15);
        return hash;
    }
    
    unsigned
    ht_generic_hash(void *cdata, const void *ptr, int numBits)
    {
        HtGenericHashSetupPtr setup = cdata;
        return one_at_a_time_hash(ptr, setup->keySize) & ~((~0U) << numBits);
    }
    
    int
    ht_generic_compare(void *cdata, const void *l, const void *r)
    {
        HtGenericHashSetupPtr setup = cdata;
        return memcmp(l, r, setup->keySize);
    }
    
    unsigned
    ht_resourceid_hash(void * cdata, const void * data, int numBits)
    {
        const XID* idPtr = data;
        XID id = *idPtr & RESOURCE_ID_MASK;
        (void) cdata;
        return HashResourceID(id, numBits);
    }
    
    int
    ht_resourceid_compare(void* cdata, const void* a, const void* b)
    {
        const XID* xa = a;
        const XID* xb = b;
        (void) cdata;
        return
            *xa < *xb ? -1 :
            *xa > *xb ? 1 :
            0;
    }
    
    void
    ht_dump_contents(HashTable ht,
                     void (*print_key)(void *opaque, void *key),
                     void (*print_value)(void *opaque, void *value),
                     void* opaque)
    {
        int c;
        int numBuckets = 1 << ht->bucketBits;
        for (c = 0; c < numBuckets; ++c) {
            BucketPtr it;
            int n = 0;
    
            printf("%d: ", c);
            xorg_list_for_each_entry(it, &ht->buckets[c], l) {
                if (n > 0) {
                    printf(", ");
                }
                print_key(opaque, it->key);
                printf("->");
                print_value(opaque, it->data);
                ++n;
            }
            printf("\n");
        }
    }