Support leaving HTDATATYPE undefined to use hash as key only hash (set)
[platform/upstream/rpm.git] / lib / rpmhash.C
1 /**
2  * \file lib/rpmhash.c
3  * Hash table implemenation
4  */
5
6 #include "system.h"
7 #include "debug.h"
8
9 #define Bucket JOIN(HASHTYPE,Buket)
10 #define Bucket_s JOIN(HASHTYPE,Buket_s)
11
12 typedef struct  Bucket_s * Bucket;
13
14 /**
15  */
16 struct  Bucket_s {
17     HTKEYTYPE key;      /*!< hash key */
18 #ifdef HTDATATYPE
19     HTDATATYPE * data;  /*!< pointer to hashed data */
20     int dataCount;      /*!< length of data (0 if unknown) */
21 #endif
22     Bucket next;        /*!< pointer to next item in bucket */
23 };
24
25 /**
26  */
27 struct HASHSTRUCT {
28     int numBuckets;                     /*!< number of hash buckets */
29     Bucket * buckets;           /*!< hash bucket array */
30     hashFunctionType fn;                /*!< generate hash value for key */
31     hashEqualityType eq;                /*!< compare hash keys for equality */
32     hashFreeKey freeKey;
33 #ifdef HTDATATYPE
34     hashFreeData freeData;
35 #endif
36 };
37
38 /**
39  * Find entry in hash table.
40  * @param ht            pointer to hash table
41  * @param key           pointer to key value
42  * @return pointer to hash bucket of key (or NULL)
43  */
44 static
45 Bucket HASHPREFIX(findEntry)(HASHTYPE ht, HTKEYTYPE key)
46 {
47     unsigned int hash;
48     Bucket b;
49
50     hash = ht->fn(key) % ht->numBuckets;
51     b = ht->buckets[hash];
52
53     while (b && b->key && ht->eq(b->key, key))
54         b = b->next;
55
56     return b;
57 }
58
59 HASHTYPE HASHPREFIX(Create)(int numBuckets,
60                             hashFunctionType fn, hashEqualityType eq,
61                             hashFreeKey freeKey
62 #ifdef HTDATATYPE
63 , hashFreeData freeData
64 #endif
65 )
66 {
67     HASHTYPE ht;
68
69     ht = xmalloc(sizeof(*ht));
70     ht->numBuckets = numBuckets;
71     ht->buckets = xcalloc(numBuckets, sizeof(*ht->buckets));
72     ht->freeKey = freeKey;
73 #ifdef HTDATATYPE
74     ht->freeData = freeData;
75 #endif
76     ht->fn = fn;
77     ht->eq = eq;
78     return ht;
79 }
80
81 void HASHPREFIX(AddEntry)(HASHTYPE ht, HTKEYTYPE key
82 #ifdef HTDATATYPE
83 , HTDATATYPE data
84 #endif
85 )
86 {
87     unsigned int hash;
88     Bucket b;
89
90     hash = ht->fn(key) % ht->numBuckets;
91     b = ht->buckets[hash];
92
93     while (b && b->key && ht->eq(b->key, key))
94         b = b->next;
95
96     if (b == NULL) {
97         b = xmalloc(sizeof(*b));
98         b->key = key;
99 #ifdef HTDATATYPE
100         b->dataCount = 0;
101         b->data = NULL;
102 #endif
103         b->next = ht->buckets[hash];
104         ht->buckets[hash] = b;
105     }
106
107 #ifdef HTDATATYPE
108     b->data = xrealloc(b->data, sizeof(*b->data) * (b->dataCount + 1));
109     b->data[b->dataCount++] = data;
110 #endif
111 }
112
113 HASHTYPE HASHPREFIX(Free)(HASHTYPE ht)
114 {
115     Bucket b, n;
116     int i;
117
118     for (i = 0; i < ht->numBuckets; i++) {
119         b = ht->buckets[i];
120         if (b == NULL)
121             continue;
122         ht->buckets[i] = NULL;
123         if (ht->freeKey)
124             b->key = ht->freeKey(b->key);
125
126         do {
127             n = b->next;
128 #ifdef HTDATATYPE
129             if (b->data) {
130                 if (ht->freeData) {
131                   int j;
132                   for (j=0; j < b->dataCount; j++ ) {
133                     b->data[j] = ht->freeData(b->data[j]);
134                   }
135                 }
136                 b->data = _free(b->data);
137             }
138 #endif
139             b = _free(b);
140         } while ((b = n) != NULL);
141     }
142
143     ht->buckets = _free(ht->buckets);
144     ht = _free(ht);
145
146     return NULL;
147 }
148
149 int HASHPREFIX(HasEntry)(HASHTYPE ht, HTKEYTYPE key)
150 {
151     Bucket b;
152
153     if (!(b = HASHPREFIX(findEntry)(ht, key))) return 0; else return 1;
154 }
155
156 #ifdef HTDATATYPE
157
158 int HASHPREFIX(GetEntry)(HASHTYPE ht, HTKEYTYPE key, HTDATATYPE** data,
159                int * dataCount, HTKEYTYPE* tableKey)
160 {
161     Bucket b;
162     int rc = ((b = HASHPREFIX(findEntry)(ht, key)) != NULL);
163
164     if (data)
165         *data = rc ? b->data : NULL;
166     if (dataCount)
167         *dataCount = rc ? b->dataCount : 0;
168     if (tableKey)
169         *tableKey = rc ? b->key : NULL;
170
171     return rc;
172 }
173
174 void HASHPREFIX(PrintStats)(HASHTYPE ht) {
175     int i;
176     Bucket bucket;
177
178     int hashcnt=0, bucketcnt=0, datacnt=0;
179     int maxbuckets=0;
180
181     for (i=0; i<ht->numBuckets; i++) {
182         int buckets = 0;
183         for (bucket=ht->buckets[i]; bucket; bucket=bucket->next){
184             buckets++;
185 #ifdef HTDATATYPE
186             datacnt += bucket->dataCount;
187 #endif
188         }
189         if (maxbuckets < buckets) maxbuckets = buckets;
190         if (buckets) hashcnt++;
191         bucketcnt += buckets;
192     }
193     fprintf(stderr, "Hashsize: %i\n", ht->numBuckets);
194     fprintf(stderr, "Hashbuckets: %i\n", hashcnt);
195     fprintf(stderr, "Keys: %i\n", bucketcnt);
196     fprintf(stderr, "Values: %i\n", datacnt);
197     fprintf(stderr, "Max Keys/Bucket: %i\n", maxbuckets);
198 }
199
200 #endif