xref: /OK3568_Linux_fs/external/xserver/Xext/hashtable.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun #ifdef HAVE_DIX_CONFIG_H
2*4882a593Smuzhiyun #include <dix-config.h>
3*4882a593Smuzhiyun #endif
4*4882a593Smuzhiyun 
5*4882a593Smuzhiyun #include <stdlib.h>
6*4882a593Smuzhiyun #include "misc.h"
7*4882a593Smuzhiyun #include "hashtable.h"
8*4882a593Smuzhiyun 
9*4882a593Smuzhiyun /* HashResourceID */
10*4882a593Smuzhiyun #include "resource.h"
11*4882a593Smuzhiyun 
12*4882a593Smuzhiyun #define INITHASHSIZE 6
13*4882a593Smuzhiyun #define MAXHASHSIZE 11
14*4882a593Smuzhiyun 
15*4882a593Smuzhiyun struct HashTableRec {
16*4882a593Smuzhiyun     int             keySize;
17*4882a593Smuzhiyun     int             dataSize;
18*4882a593Smuzhiyun 
19*4882a593Smuzhiyun     int             elements;   /* number of elements inserted */
20*4882a593Smuzhiyun     int             bucketBits; /* number of buckets is 1 << bucketBits */
21*4882a593Smuzhiyun     struct xorg_list *buckets;  /* array of bucket list heads */
22*4882a593Smuzhiyun 
23*4882a593Smuzhiyun     HashFunc        hash;
24*4882a593Smuzhiyun     HashCompareFunc compare;
25*4882a593Smuzhiyun 
26*4882a593Smuzhiyun     void            *cdata;
27*4882a593Smuzhiyun };
28*4882a593Smuzhiyun 
29*4882a593Smuzhiyun typedef struct {
30*4882a593Smuzhiyun     struct xorg_list l;
31*4882a593Smuzhiyun     void *key;
32*4882a593Smuzhiyun     void *data;
33*4882a593Smuzhiyun } BucketRec, *BucketPtr;
34*4882a593Smuzhiyun 
35*4882a593Smuzhiyun HashTable
ht_create(int keySize,int dataSize,HashFunc hash,HashCompareFunc compare,void * cdata)36*4882a593Smuzhiyun ht_create(int             keySize,
37*4882a593Smuzhiyun           int             dataSize,
38*4882a593Smuzhiyun           HashFunc        hash,
39*4882a593Smuzhiyun           HashCompareFunc compare,
40*4882a593Smuzhiyun           void            *cdata)
41*4882a593Smuzhiyun {
42*4882a593Smuzhiyun     int c;
43*4882a593Smuzhiyun     int numBuckets;
44*4882a593Smuzhiyun     HashTable ht = malloc(sizeof(struct HashTableRec));
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun     if (!ht) {
47*4882a593Smuzhiyun         return NULL;
48*4882a593Smuzhiyun     }
49*4882a593Smuzhiyun 
50*4882a593Smuzhiyun     ht->keySize = keySize;
51*4882a593Smuzhiyun     ht->dataSize = dataSize;
52*4882a593Smuzhiyun     ht->hash = hash;
53*4882a593Smuzhiyun     ht->compare = compare;
54*4882a593Smuzhiyun     ht->elements = 0;
55*4882a593Smuzhiyun     ht->bucketBits = INITHASHSIZE;
56*4882a593Smuzhiyun     numBuckets = 1 << ht->bucketBits;
57*4882a593Smuzhiyun     ht->buckets = xallocarray(numBuckets, sizeof(*ht->buckets));
58*4882a593Smuzhiyun     ht->cdata = cdata;
59*4882a593Smuzhiyun 
60*4882a593Smuzhiyun     if (ht->buckets) {
61*4882a593Smuzhiyun         for (c = 0; c < numBuckets; ++c) {
62*4882a593Smuzhiyun             xorg_list_init(&ht->buckets[c]);
63*4882a593Smuzhiyun         }
64*4882a593Smuzhiyun         return ht;
65*4882a593Smuzhiyun     } else {
66*4882a593Smuzhiyun         free(ht);
67*4882a593Smuzhiyun         return NULL;
68*4882a593Smuzhiyun     }
69*4882a593Smuzhiyun }
70*4882a593Smuzhiyun 
71*4882a593Smuzhiyun void
ht_destroy(HashTable ht)72*4882a593Smuzhiyun ht_destroy(HashTable ht)
73*4882a593Smuzhiyun {
74*4882a593Smuzhiyun     int c;
75*4882a593Smuzhiyun     BucketPtr it, tmp;
76*4882a593Smuzhiyun     int numBuckets = 1 << ht->bucketBits;
77*4882a593Smuzhiyun     for (c = 0; c < numBuckets; ++c) {
78*4882a593Smuzhiyun         xorg_list_for_each_entry_safe(it, tmp, &ht->buckets[c], l) {
79*4882a593Smuzhiyun             xorg_list_del(&it->l);
80*4882a593Smuzhiyun             free(it->key);
81*4882a593Smuzhiyun             free(it->data);
82*4882a593Smuzhiyun             free(it);
83*4882a593Smuzhiyun         }
84*4882a593Smuzhiyun     }
85*4882a593Smuzhiyun     free(ht->buckets);
86*4882a593Smuzhiyun     free(ht);
87*4882a593Smuzhiyun }
88*4882a593Smuzhiyun 
89*4882a593Smuzhiyun static Bool
double_size(HashTable ht)90*4882a593Smuzhiyun double_size(HashTable ht)
91*4882a593Smuzhiyun {
92*4882a593Smuzhiyun     struct xorg_list *newBuckets;
93*4882a593Smuzhiyun     int numBuckets = 1 << ht->bucketBits;
94*4882a593Smuzhiyun     int newBucketBits = ht->bucketBits + 1;
95*4882a593Smuzhiyun     int newNumBuckets = 1 << newBucketBits;
96*4882a593Smuzhiyun     int c;
97*4882a593Smuzhiyun 
98*4882a593Smuzhiyun     newBuckets = xallocarray(newNumBuckets, sizeof(*ht->buckets));
99*4882a593Smuzhiyun     if (newBuckets) {
100*4882a593Smuzhiyun         for (c = 0; c < newNumBuckets; ++c) {
101*4882a593Smuzhiyun             xorg_list_init(&newBuckets[c]);
102*4882a593Smuzhiyun         }
103*4882a593Smuzhiyun 
104*4882a593Smuzhiyun         for (c = 0; c < numBuckets; ++c) {
105*4882a593Smuzhiyun             BucketPtr it, tmp;
106*4882a593Smuzhiyun             xorg_list_for_each_entry_safe(it, tmp, &ht->buckets[c], l) {
107*4882a593Smuzhiyun                 struct xorg_list *newBucket =
108*4882a593Smuzhiyun                     &newBuckets[ht->hash(ht->cdata, it->key, newBucketBits)];
109*4882a593Smuzhiyun                 xorg_list_del(&it->l);
110*4882a593Smuzhiyun                 xorg_list_add(&it->l, newBucket);
111*4882a593Smuzhiyun             }
112*4882a593Smuzhiyun         }
113*4882a593Smuzhiyun         free(ht->buckets);
114*4882a593Smuzhiyun 
115*4882a593Smuzhiyun         ht->buckets = newBuckets;
116*4882a593Smuzhiyun         ht->bucketBits = newBucketBits;
117*4882a593Smuzhiyun         return TRUE;
118*4882a593Smuzhiyun     } else {
119*4882a593Smuzhiyun         return FALSE;
120*4882a593Smuzhiyun     }
121*4882a593Smuzhiyun }
122*4882a593Smuzhiyun 
123*4882a593Smuzhiyun void *
ht_add(HashTable ht,const void * key)124*4882a593Smuzhiyun ht_add(HashTable ht, const void *key)
125*4882a593Smuzhiyun {
126*4882a593Smuzhiyun     unsigned index = ht->hash(ht->cdata, key, ht->bucketBits);
127*4882a593Smuzhiyun     struct xorg_list *bucket = &ht->buckets[index];
128*4882a593Smuzhiyun     BucketRec *elem = calloc(1, sizeof(BucketRec));
129*4882a593Smuzhiyun     if (!elem) {
130*4882a593Smuzhiyun         goto outOfMemory;
131*4882a593Smuzhiyun     }
132*4882a593Smuzhiyun     elem->key = malloc(ht->keySize);
133*4882a593Smuzhiyun     if (!elem->key) {
134*4882a593Smuzhiyun         goto outOfMemory;
135*4882a593Smuzhiyun     }
136*4882a593Smuzhiyun     /* we avoid signaling an out-of-memory error if dataSize is 0 */
137*4882a593Smuzhiyun     elem->data = calloc(1, ht->dataSize);
138*4882a593Smuzhiyun     if (ht->dataSize && !elem->data) {
139*4882a593Smuzhiyun         goto outOfMemory;
140*4882a593Smuzhiyun     }
141*4882a593Smuzhiyun     xorg_list_add(&elem->l, bucket);
142*4882a593Smuzhiyun     ++ht->elements;
143*4882a593Smuzhiyun 
144*4882a593Smuzhiyun     memcpy(elem->key, key, ht->keySize);
145*4882a593Smuzhiyun 
146*4882a593Smuzhiyun     if (ht->elements > 4 * (1 << ht->bucketBits) &&
147*4882a593Smuzhiyun         ht->bucketBits < MAXHASHSIZE) {
148*4882a593Smuzhiyun         if (!double_size(ht)) {
149*4882a593Smuzhiyun             --ht->elements;
150*4882a593Smuzhiyun             xorg_list_del(&elem->l);
151*4882a593Smuzhiyun             goto outOfMemory;
152*4882a593Smuzhiyun         }
153*4882a593Smuzhiyun     }
154*4882a593Smuzhiyun 
155*4882a593Smuzhiyun     /* if memory allocation has failed due to dataSize being 0, return
156*4882a593Smuzhiyun        a "dummy" pointer pointing at the of the key */
157*4882a593Smuzhiyun     return elem->data ? elem->data : ((char*) elem->key + ht->keySize);
158*4882a593Smuzhiyun 
159*4882a593Smuzhiyun  outOfMemory:
160*4882a593Smuzhiyun     if (elem) {
161*4882a593Smuzhiyun         free(elem->key);
162*4882a593Smuzhiyun         free(elem->data);
163*4882a593Smuzhiyun         free(elem);
164*4882a593Smuzhiyun     }
165*4882a593Smuzhiyun 
166*4882a593Smuzhiyun     return NULL;
167*4882a593Smuzhiyun }
168*4882a593Smuzhiyun 
169*4882a593Smuzhiyun void
ht_remove(HashTable ht,const void * key)170*4882a593Smuzhiyun ht_remove(HashTable ht, const void *key)
171*4882a593Smuzhiyun {
172*4882a593Smuzhiyun     unsigned index = ht->hash(ht->cdata, key, ht->bucketBits);
173*4882a593Smuzhiyun     struct xorg_list *bucket = &ht->buckets[index];
174*4882a593Smuzhiyun     BucketPtr it;
175*4882a593Smuzhiyun 
176*4882a593Smuzhiyun     xorg_list_for_each_entry(it, bucket, l) {
177*4882a593Smuzhiyun         if (ht->compare(ht->cdata, key, it->key) == 0) {
178*4882a593Smuzhiyun             xorg_list_del(&it->l);
179*4882a593Smuzhiyun             --ht->elements;
180*4882a593Smuzhiyun             free(it->key);
181*4882a593Smuzhiyun             free(it->data);
182*4882a593Smuzhiyun             free(it);
183*4882a593Smuzhiyun             return;
184*4882a593Smuzhiyun         }
185*4882a593Smuzhiyun     }
186*4882a593Smuzhiyun }
187*4882a593Smuzhiyun 
188*4882a593Smuzhiyun void *
ht_find(HashTable ht,const void * key)189*4882a593Smuzhiyun ht_find(HashTable ht, const void *key)
190*4882a593Smuzhiyun {
191*4882a593Smuzhiyun     unsigned index = ht->hash(ht->cdata, key, ht->bucketBits);
192*4882a593Smuzhiyun     struct xorg_list *bucket = &ht->buckets[index];
193*4882a593Smuzhiyun     BucketPtr it;
194*4882a593Smuzhiyun 
195*4882a593Smuzhiyun     xorg_list_for_each_entry(it, bucket, l) {
196*4882a593Smuzhiyun         if (ht->compare(ht->cdata, key, it->key) == 0) {
197*4882a593Smuzhiyun             return it->data ? it->data : ((char*) it->key + ht->keySize);
198*4882a593Smuzhiyun         }
199*4882a593Smuzhiyun     }
200*4882a593Smuzhiyun 
201*4882a593Smuzhiyun     return NULL;
202*4882a593Smuzhiyun }
203*4882a593Smuzhiyun 
204*4882a593Smuzhiyun void
ht_dump_distribution(HashTable ht)205*4882a593Smuzhiyun ht_dump_distribution(HashTable ht)
206*4882a593Smuzhiyun {
207*4882a593Smuzhiyun     int c;
208*4882a593Smuzhiyun     int numBuckets = 1 << ht->bucketBits;
209*4882a593Smuzhiyun     for (c = 0; c < numBuckets; ++c) {
210*4882a593Smuzhiyun         BucketPtr it;
211*4882a593Smuzhiyun         int n = 0;
212*4882a593Smuzhiyun 
213*4882a593Smuzhiyun         xorg_list_for_each_entry(it, &ht->buckets[c], l) {
214*4882a593Smuzhiyun             ++n;
215*4882a593Smuzhiyun         }
216*4882a593Smuzhiyun         printf("%d: %d\n", c, n);
217*4882a593Smuzhiyun     }
218*4882a593Smuzhiyun }
219*4882a593Smuzhiyun 
220*4882a593Smuzhiyun /* Picked the function from http://burtleburtle.net/bob/hash/doobs.html by
221*4882a593Smuzhiyun    Bob Jenkins, which is released in public domain */
222*4882a593Smuzhiyun static CARD32
one_at_a_time_hash(const void * data,int len)223*4882a593Smuzhiyun one_at_a_time_hash(const void *data, int len)
224*4882a593Smuzhiyun {
225*4882a593Smuzhiyun     CARD32 hash;
226*4882a593Smuzhiyun     int i;
227*4882a593Smuzhiyun     const char *key = data;
228*4882a593Smuzhiyun     for (hash=0, i=0; i<len; ++i) {
229*4882a593Smuzhiyun         hash += key[i];
230*4882a593Smuzhiyun         hash += (hash << 10);
231*4882a593Smuzhiyun         hash ^= (hash >> 6);
232*4882a593Smuzhiyun     }
233*4882a593Smuzhiyun     hash += (hash << 3);
234*4882a593Smuzhiyun     hash ^= (hash >> 11);
235*4882a593Smuzhiyun     hash += (hash << 15);
236*4882a593Smuzhiyun     return hash;
237*4882a593Smuzhiyun }
238*4882a593Smuzhiyun 
239*4882a593Smuzhiyun unsigned
ht_generic_hash(void * cdata,const void * ptr,int numBits)240*4882a593Smuzhiyun ht_generic_hash(void *cdata, const void *ptr, int numBits)
241*4882a593Smuzhiyun {
242*4882a593Smuzhiyun     HtGenericHashSetupPtr setup = cdata;
243*4882a593Smuzhiyun     return one_at_a_time_hash(ptr, setup->keySize) & ~((~0) << numBits);
244*4882a593Smuzhiyun }
245*4882a593Smuzhiyun 
246*4882a593Smuzhiyun int
ht_generic_compare(void * cdata,const void * l,const void * r)247*4882a593Smuzhiyun ht_generic_compare(void *cdata, const void *l, const void *r)
248*4882a593Smuzhiyun {
249*4882a593Smuzhiyun     HtGenericHashSetupPtr setup = cdata;
250*4882a593Smuzhiyun     return memcmp(l, r, setup->keySize);
251*4882a593Smuzhiyun }
252*4882a593Smuzhiyun 
253*4882a593Smuzhiyun unsigned
ht_resourceid_hash(void * cdata,const void * data,int numBits)254*4882a593Smuzhiyun ht_resourceid_hash(void * cdata, const void * data, int numBits)
255*4882a593Smuzhiyun {
256*4882a593Smuzhiyun     const XID* idPtr = data;
257*4882a593Smuzhiyun     XID id = *idPtr & RESOURCE_ID_MASK;
258*4882a593Smuzhiyun     (void) cdata;
259*4882a593Smuzhiyun     return HashResourceID(id, numBits);
260*4882a593Smuzhiyun }
261*4882a593Smuzhiyun 
262*4882a593Smuzhiyun int
ht_resourceid_compare(void * cdata,const void * a,const void * b)263*4882a593Smuzhiyun ht_resourceid_compare(void* cdata, const void* a, const void* b)
264*4882a593Smuzhiyun {
265*4882a593Smuzhiyun     const XID* xa = a;
266*4882a593Smuzhiyun     const XID* xb = b;
267*4882a593Smuzhiyun     (void) cdata;
268*4882a593Smuzhiyun     return
269*4882a593Smuzhiyun         *xa < *xb ? -1 :
270*4882a593Smuzhiyun         *xa > *xb ? 1 :
271*4882a593Smuzhiyun         0;
272*4882a593Smuzhiyun }
273*4882a593Smuzhiyun 
274*4882a593Smuzhiyun void
ht_dump_contents(HashTable ht,void (* print_key)(void * opaque,void * key),void (* print_value)(void * opaque,void * value),void * opaque)275*4882a593Smuzhiyun ht_dump_contents(HashTable ht,
276*4882a593Smuzhiyun                  void (*print_key)(void *opaque, void *key),
277*4882a593Smuzhiyun                  void (*print_value)(void *opaque, void *value),
278*4882a593Smuzhiyun                  void* opaque)
279*4882a593Smuzhiyun {
280*4882a593Smuzhiyun     int c;
281*4882a593Smuzhiyun     int numBuckets = 1 << ht->bucketBits;
282*4882a593Smuzhiyun     for (c = 0; c < numBuckets; ++c) {
283*4882a593Smuzhiyun         BucketPtr it;
284*4882a593Smuzhiyun         int n = 0;
285*4882a593Smuzhiyun 
286*4882a593Smuzhiyun         printf("%d: ", c);
287*4882a593Smuzhiyun         xorg_list_for_each_entry(it, &ht->buckets[c], l) {
288*4882a593Smuzhiyun             if (n > 0) {
289*4882a593Smuzhiyun                 printf(", ");
290*4882a593Smuzhiyun             }
291*4882a593Smuzhiyun             print_key(opaque, it->key);
292*4882a593Smuzhiyun             printf("->");
293*4882a593Smuzhiyun             print_value(opaque, it->data);
294*4882a593Smuzhiyun             ++n;
295*4882a593Smuzhiyun         }
296*4882a593Smuzhiyun         printf("\n");
297*4882a593Smuzhiyun     }
298*4882a593Smuzhiyun }
299