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