Add support for global LDFLAGS
[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 <stdio.h>
8 #include "debug.h"
9
10 #define Bucket JOIN(HASHTYPE,Buket)
11 #define Bucket_s JOIN(HASHTYPE,Buket_s)
12
13 typedef struct  Bucket_s * Bucket;
14
15 /**
16  */
17 struct  Bucket_s {
18     Bucket next;        /*!< pointer to next item in bucket */
19     HTKEYTYPE key;      /*!< hash key */
20 #ifdef HTDATATYPE
21     int dataCount;      /*!< data entries */
22     HTDATATYPE data[1]; /*!< data - grows by resizing whole bucket */
23 #endif
24 };
25
26 /**
27  */
28 struct HASHSTRUCT {
29     int numBuckets;                     /*!< number of hash buckets */
30     Bucket * buckets;                   /*!< hash bucket array */
31     hashFunctionType fn;                /*!< generate hash value for key */
32     hashEqualityType eq;                /*!< compare hash keys for equality */
33     hashFreeKey freeKey;
34     int bucketCount;                    /*!< number of used buckets */
35     int keyCount;                       /*!< number of keys */
36 #ifdef HTDATATYPE
37     int dataCount;                      /*!< number of data entries */
38     hashFreeData freeData;
39 #endif
40 };
41
42 /**
43  * Find entry in hash table.
44  * @param ht            pointer to hash table
45  * @param key           pointer to key value
46  * @param keyHash       key hash
47  * @return pointer to hash bucket of key (or NULL)
48  */
49 static
50 Bucket HASHPREFIX(findEntry)(HASHTYPE ht, HTKEYTYPE key, unsigned int keyHash)
51 {
52     unsigned int hash = keyHash % ht->numBuckets;
53     Bucket b = ht->buckets[hash];
54
55     while (b && ht->eq(b->key, key))
56         b = b->next;
57
58     return b;
59 }
60
61 HASHTYPE HASHPREFIX(Create)(int numBuckets,
62                             hashFunctionType fn, hashEqualityType eq,
63                             hashFreeKey freeKey
64 #ifdef HTDATATYPE
65 , hashFreeData freeData
66 #endif
67 )
68 {
69     HASHTYPE ht;
70
71     ht = xmalloc(sizeof(*ht));
72     ht->numBuckets = numBuckets;
73     ht->buckets = xcalloc(numBuckets, sizeof(*ht->buckets));
74     ht->freeKey = freeKey;
75 #ifdef HTDATATYPE
76     ht->freeData = freeData;
77     ht->dataCount = 0;
78 #endif
79     ht->fn = fn;
80     ht->eq = eq;
81     ht->bucketCount = ht->keyCount = 0;
82     return ht;
83 }
84
85 static void HASHPREFIX(Resize)(HASHTYPE ht, int numBuckets) {
86     Bucket * buckets = xcalloc(numBuckets, sizeof(*ht->buckets));
87
88     for (int i=0; i<ht->numBuckets; i++) {
89         Bucket b = ht->buckets[i];
90         Bucket nextB;
91         while (b != NULL) {
92             unsigned int hash = ht->fn(b->key) % numBuckets;
93             nextB = b->next;
94             b->next = buckets[hash];
95             buckets[hash] = b;
96             b = nextB;
97         }
98     }
99     free(ht->buckets);
100     ht->buckets = buckets;
101     ht->numBuckets = numBuckets;
102 }
103
104 unsigned int HASHPREFIX(KeyHash)(HASHTYPE ht, HTKEYTYPE key)
105 {
106     return ht->fn(key);
107 }
108
109 void HASHPREFIX(AddHEntry)(HASHTYPE ht, HTKEYTYPE key, unsigned int keyHash
110 #ifdef HTDATATYPE
111 , HTDATATYPE data
112 #endif
113 )
114 {
115     unsigned int hash = keyHash % ht->numBuckets;
116     Bucket b = ht->buckets[hash];
117 #ifdef HTDATATYPE
118     Bucket * b_addr = ht->buckets + hash;
119 #endif
120
121     if (b == NULL) {
122         ht->bucketCount += 1;
123     }
124
125     while (b && ht->eq(b->key, key)) {
126 #ifdef HTDATATYPE
127         b_addr = &(b->next);
128 #endif
129         b = b->next;
130     }
131
132     if (b == NULL) {
133         ht->keyCount += 1;
134         b = xmalloc(sizeof(*b));
135         b->key = key;
136 #ifdef HTDATATYPE
137         b->dataCount = 1;
138         b->data[0] = data;
139 #endif
140         b->next = ht->buckets[hash];
141         ht->buckets[hash] = b;
142     }
143 #ifdef HTDATATYPE
144     else {
145         // resizing bucket TODO: increase exponentially
146         // Bucket_s already contains space for one dataset
147         b = *b_addr = xrealloc(
148             b, sizeof(*b) + sizeof(b->data[0]) * (b->dataCount));
149         // though increasing dataCount after the resize
150         b->data[b->dataCount++] = data;
151     }
152     ht->dataCount += 1;
153 #endif
154     if (ht->keyCount > ht->numBuckets) {
155         HASHPREFIX(Resize)(ht, ht->numBuckets * 2);
156     }
157 }
158
159 void HASHPREFIX(AddEntry)(HASHTYPE ht, HTKEYTYPE key
160 #ifdef HTDATATYPE
161 , HTDATATYPE data
162 #endif
163 )
164 {
165 #ifdef HTDATATYPE
166     HASHPREFIX(AddHEntry)(ht, key, ht->fn(key), data);
167 #else
168     HASHPREFIX(AddHEntry)(ht, key, ht->fn(key));
169 #endif
170 }
171
172 void HASHPREFIX(Empty)( HASHTYPE ht)
173 {
174     Bucket b, n;
175     int i;
176
177     if (ht->bucketCount == 0) return;
178
179     for (i = 0; i < ht->numBuckets; i++) {
180         b = ht->buckets[i];
181         if (b == NULL)
182             continue;
183         ht->buckets[i] = NULL;
184
185         do {
186             n = b->next;
187             if (ht->freeKey)
188                 b->key = ht->freeKey(b->key);
189 #ifdef HTDATATYPE
190             if (ht->freeData) {
191                 int j;
192                 for (j=0; j < b->dataCount; j++ ) {
193                     b->data[j] = ht->freeData(b->data[j]);
194                 }
195             }
196 #endif
197             b = _free(b);
198         } while ((b = n) != NULL);
199     }
200     ht->bucketCount = 0;
201     ht->keyCount = 0;
202 #ifdef HTDATATYPE
203     ht->dataCount = 0;
204 #endif
205 }
206
207 HASHTYPE HASHPREFIX(Free)(HASHTYPE ht)
208 {
209     if (ht==NULL)
210         return ht;
211     HASHPREFIX(Empty)(ht);
212     ht->buckets = _free(ht->buckets);
213     ht = _free(ht);
214
215     return NULL;
216 }
217
218 int HASHPREFIX(HasHEntry)(HASHTYPE ht, HTKEYTYPE key, unsigned int keyHash)
219 {
220     Bucket b;
221
222     if (!(b = HASHPREFIX(findEntry)(ht, key, keyHash))) return 0; else return 1;
223 }
224
225 int HASHPREFIX(HasEntry)(HASHTYPE ht, HTKEYTYPE key)
226 {
227     return HASHPREFIX(HasHEntry)(ht, key, ht->fn(key));
228 }
229
230 int HASHPREFIX(GetHEntry)(HASHTYPE ht, HTKEYTYPE key, unsigned int keyHash,
231 #ifdef HTDATATYPE
232                          HTDATATYPE** data, int * dataCount,
233 #endif
234                          HTKEYTYPE* tableKey)
235 {
236     Bucket b;
237     int rc = ((b = HASHPREFIX(findEntry)(ht, key, keyHash)) != NULL);
238
239 #ifdef HTDATATYPE
240     if (data)
241         *data = rc ? b->data : NULL;
242     if (dataCount)
243         *dataCount = rc ? b->dataCount : 0;
244 #endif
245     if (tableKey && rc)
246         *tableKey = b->key;
247
248     return rc;
249 }
250
251 int HASHPREFIX(GetEntry)(HASHTYPE ht, HTKEYTYPE key,
252 #ifdef HTDATATYPE
253                          HTDATATYPE** data, int * dataCount,
254 #endif
255                          HTKEYTYPE* tableKey)
256 {
257     return HASHPREFIX(GetHEntry)(ht, key, ht->fn(key),
258 #ifdef HTDATATYPE
259                                  data, dataCount,
260 #endif
261                                  tableKey);
262 }
263
264 unsigned int HASHPREFIX(NumBuckets)(HASHTYPE ht) {
265     return ht->numBuckets;
266 }
267
268 unsigned int HASHPREFIX(UsedBuckets)(HASHTYPE ht) {
269     return ht->bucketCount;
270 }
271
272 unsigned int HASHPREFIX(NumKeys)(HASHTYPE ht) {
273     return ht->keyCount;
274 }
275
276 #ifdef HTDATATYPE
277 unsigned int HASHPREFIX(NumData)(HASHTYPE ht) {
278     return ht->dataCount;
279 }
280 #endif
281
282
283 void HASHPREFIX(PrintStats)(HASHTYPE ht) {
284     int i;
285     Bucket bucket;
286
287     int hashcnt=0, bucketcnt=0, datacnt=0;
288     int maxbuckets=0;
289
290     for (i=0; i<ht->numBuckets; i++) {
291         int buckets = 0;
292         for (bucket=ht->buckets[i]; bucket; bucket=bucket->next){
293             buckets++;
294 #ifdef HTDATATYPE
295             datacnt += bucket->dataCount;
296 #endif
297         }
298         if (maxbuckets < buckets) maxbuckets = buckets;
299         if (buckets) hashcnt++;
300         bucketcnt += buckets;
301     }
302     fprintf(stderr, "Hashsize: %i\n", ht->numBuckets);
303     fprintf(stderr, "Hashbuckets: %i\n", hashcnt);
304     fprintf(stderr, "Keys: %i\n", bucketcnt);
305     fprintf(stderr, "Values: %i\n", datacnt);
306     fprintf(stderr, "Max Keys/Bucket: %i\n", maxbuckets);
307 }