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