/** * \file lib/rpmhash.c * Hash table implemenation */ #include "system.h" #include "debug.h" #define Bucket JOIN(HASHTYPE,Buket) #define Bucket_s JOIN(HASHTYPE,Buket_s) typedef struct Bucket_s * Bucket; /** */ struct Bucket_s { HTKEYTYPE key; /*!< hash key */ HTDATATYPE * data; /*!< pointer to hashed data */ int dataCount; /*!< length of data (0 if unknown) */ Bucket next; /*!< pointer to next item in bucket */ }; /** */ struct HASHSTRUCT { int numBuckets; /*!< number of hash buckets */ Bucket * buckets; /*!< hash bucket array */ hashFunctionType fn; /*!< generate hash value for key */ hashEqualityType eq; /*!< compare hash keys for equality */ hashFreeKey freeKey; hashFreeData freeData; }; /** * Find entry in hash table. * @param ht pointer to hash table * @param key pointer to key value * @return pointer to hash bucket of key (or NULL) */ static Bucket HASHPREFIX(findEntry)(HASHTYPE ht, HTKEYTYPE key) { unsigned int hash; Bucket b; hash = ht->fn(key) % ht->numBuckets; b = ht->buckets[hash]; while (b && b->key && ht->eq(b->key, key)) b = b->next; return b; } HASHTYPE HASHPREFIX(Create)(int numBuckets, hashFunctionType fn, hashEqualityType eq, hashFreeKey freeKey, hashFreeData freeData) { HASHTYPE ht; ht = xmalloc(sizeof(*ht)); ht->numBuckets = numBuckets; ht->buckets = xcalloc(numBuckets, sizeof(*ht->buckets)); ht->freeKey = freeKey; ht->freeData = freeData; ht->fn = fn; ht->eq = eq; return ht; } void HASHPREFIX(AddEntry)(HASHTYPE ht, HTKEYTYPE key, HTDATATYPE data) { unsigned int hash; Bucket b; hash = ht->fn(key) % ht->numBuckets; b = ht->buckets[hash]; while (b && b->key && ht->eq(b->key, key)) b = b->next; if (b == NULL) { b = xmalloc(sizeof(*b)); b->key = key; b->dataCount = 0; b->next = ht->buckets[hash]; b->data = NULL; ht->buckets[hash] = b; } b->data = xrealloc(b->data, sizeof(*b->data) * (b->dataCount + 1)); b->data[b->dataCount++] = data; } HASHTYPE HASHPREFIX(Free)(HASHTYPE ht) { Bucket b, n; int i, j; for (i = 0; i < ht->numBuckets; i++) { b = ht->buckets[i]; if (b == NULL) continue; ht->buckets[i] = NULL; if (ht->freeKey) b->key = ht->freeKey(b->key); do { n = b->next; if (b->data) { if (ht->freeData) { for (j=0; j < b->dataCount; j++ ) { b->data[j] = ht->freeData(b->data[j]); } } b->data = _free(b->data); } b = _free(b); } while ((b = n) != NULL); } ht->buckets = _free(ht->buckets); ht = _free(ht); return NULL; } int HASHPREFIX(HasEntry)(HASHTYPE ht, HTKEYTYPE key) { Bucket b; if (!(b = HASHPREFIX(findEntry)(ht, key))) return 0; else return 1; } int HASHPREFIX(GetEntry)(HASHTYPE ht, HTKEYTYPE key, HTDATATYPE** data, int * dataCount, HTKEYTYPE* tableKey) { Bucket b; int rc = ((b = HASHPREFIX(findEntry)(ht, key)) != NULL); if (data) *data = rc ? b->data : NULL; if (dataCount) *dataCount = rc ? b->dataCount : 0; if (tableKey) *tableKey = rc ? b->key : NULL; return rc; } void HASHPREFIX(PrintStats)(HASHTYPE ht) { int i; Bucket bucket; int hashcnt=0, bucketcnt=0, datacnt=0; int maxbuckets=0; for (i=0; inumBuckets; i++) { int buckets = 0; for (bucket=ht->buckets[i]; bucket; bucket=bucket->next){ buckets++; datacnt += bucket->dataCount; } if (maxbuckets < buckets) maxbuckets = buckets; if (buckets) hashcnt++; bucketcnt += buckets; } fprintf(stderr, "Hashsize: %i\n", ht->numBuckets); fprintf(stderr, "Hashbuckets: %i\n", hashcnt); fprintf(stderr, "Keys: %i\n", bucketcnt); fprintf(stderr, "Values: %i\n", datacnt); fprintf(stderr, "Max Keys/Bucket: %i\n", maxbuckets); }