remove empty dir
[ghc-hetmet.git] / ghc / rts / Hash.c
1 /*-----------------------------------------------------------------------------
2  *
3  * (c) The AQUA Project, Glasgow University, 1995-1998
4  * (c) The GHC Team, 1999
5  *
6  * Dynamically expanding linear hash tables, as described in
7  * Per-\AAke Larson, ``Dynamic Hash Tables,'' CACM 31(4), April 1988,
8  * pp. 446 -- 457.
9  * -------------------------------------------------------------------------- */
10
11 #include "PosixSource.h"
12 #include "Rts.h"
13 #include "Hash.h"
14 #include "RtsUtils.h"
15
16 #include <stdlib.h>
17 #include <string.h>
18
19 #define HSEGSIZE    1024    /* Size of a single hash table segment */
20                             /* Also the minimum size of a hash table */
21 #define HDIRSIZE    1024    /* Size of the segment directory */
22                             /* Maximum hash table size is HSEGSIZE * HDIRSIZE */
23 #define HLOAD       5       /* Maximum average load of a single hash bucket */
24
25 #define HCHUNK      (1024 * sizeof(W_) / sizeof(HashList))
26                             /* Number of HashList cells to allocate in one go */
27
28
29 /* Linked list of (key, data) pairs for separate chaining */
30 struct hashlist {
31     StgWord key;
32     void *data;
33     struct hashlist *next;  /* Next cell in bucket chain (same hash value) */
34 };
35
36 typedef struct hashlist HashList;
37
38 typedef int HashFunction(HashTable *table, StgWord key);
39 typedef int CompareFunction(StgWord key1, StgWord key2);
40
41 struct hashtable {
42     int split;              /* Next bucket to split when expanding */
43     int max;                /* Max bucket of smaller table */
44     int mask1;              /* Mask for doing the mod of h_1 (smaller table) */
45     int mask2;              /* Mask for doing the mod of h_2 (larger table) */
46     int kcount;             /* Number of keys */
47     int bcount;             /* Number of buckets */
48     HashList **dir[HDIRSIZE];   /* Directory of segments */
49     HashFunction *hash;         /* hash function */
50     CompareFunction *compare;   /* key comparison function */
51 };
52
53 /* -----------------------------------------------------------------------------
54  * Hash first using the smaller table.  If the bucket is less than the
55  * next bucket to be split, re-hash using the larger table.
56  * -------------------------------------------------------------------------- */
57
58 static int
59 hashWord(HashTable *table, StgWord key)
60 {
61     int bucket;
62
63     /* Strip the boring zero bits */
64     key /= sizeof(StgWord);
65
66     /* Mod the size of the hash table (a power of 2) */
67     bucket = key & table->mask1;
68
69     if (bucket < table->split) {
70         /* Mod the size of the expanded hash table (also a power of 2) */
71         bucket = key & table->mask2;
72     }
73     return bucket;
74 }
75
76 static int
77 hashStr(HashTable *table, char *key)
78 {
79     int h, bucket;
80     char *s;
81
82     s = key;
83     for (h=0; *s; s++) {
84         h *= 128;
85         h += *s;
86         h = h % 1048583;        /* some random large prime */
87     }
88
89     /* Mod the size of the hash table (a power of 2) */
90     bucket = h & table->mask1;
91
92     if (bucket < table->split) {
93         /* Mod the size of the expanded hash table (also a power of 2) */
94         bucket = h & table->mask2;
95     }
96
97     return bucket;
98 }
99
100 static int
101 compareWord(StgWord key1, StgWord key2)
102 {
103     return (key1 == key2);
104 }
105
106 static int
107 compareStr(StgWord key1, StgWord key2)
108 {
109     return (strcmp((char *)key1, (char *)key2) == 0);
110 }
111
112
113 /* -----------------------------------------------------------------------------
114  * Allocate a new segment of the dynamically growing hash table.
115  * -------------------------------------------------------------------------- */
116
117 static void
118 allocSegment(HashTable *table, int segment)
119 {
120     table->dir[segment] = stgMallocBytes(HSEGSIZE * sizeof(HashList *), 
121                                          "allocSegment");
122 }
123
124
125 /* -----------------------------------------------------------------------------
126  * Expand the larger hash table by one bucket, and split one bucket
127  * from the smaller table into two parts.  Only the bucket referenced
128  * by @table->split@ is affected by the expansion.
129  * -------------------------------------------------------------------------- */
130
131 static void
132 expand(HashTable *table)
133 {
134     int oldsegment;
135     int oldindex;
136     int newbucket;
137     int newsegment;
138     int newindex;
139     HashList *hl;
140     HashList *next;
141     HashList *old, *new;
142
143     if (table->split + table->max >= HDIRSIZE * HSEGSIZE)
144         /* Wow!  That's big.  Too big, so don't expand. */
145         return;
146
147     /* Calculate indices of bucket to split */
148     oldsegment = table->split / HSEGSIZE;
149     oldindex = table->split % HSEGSIZE;
150
151     newbucket = table->max + table->split;
152
153     /* And the indices of the new bucket */
154     newsegment = newbucket / HSEGSIZE;
155     newindex = newbucket % HSEGSIZE;
156
157     if (newindex == 0)
158         allocSegment(table, newsegment);
159
160     if (++table->split == table->max) {
161         table->split = 0;
162         table->max *= 2;
163         table->mask1 = table->mask2;
164         table->mask2 = table->mask2 << 1 | 1;
165     }
166     table->bcount++;
167
168     /* Split the bucket, paying no attention to the original order */
169
170     old = new = NULL;
171     for (hl = table->dir[oldsegment][oldindex]; hl != NULL; hl = next) {
172         next = hl->next;
173         if (table->hash(table, hl->key) == newbucket) {
174             hl->next = new;
175             new = hl;
176         } else {
177             hl->next = old;
178             old = hl;
179         }
180     }
181     table->dir[oldsegment][oldindex] = old;
182     table->dir[newsegment][newindex] = new;
183
184     return;
185 }
186
187 void *
188 lookupHashTable(HashTable *table, StgWord key)
189 {
190     int bucket;
191     int segment;
192     int index;
193     HashList *hl;
194
195     bucket = table->hash(table, key);
196     segment = bucket / HSEGSIZE;
197     index = bucket % HSEGSIZE;
198
199     for (hl = table->dir[segment][index]; hl != NULL; hl = hl->next)
200         if (table->compare(hl->key, key))
201             return hl->data;
202
203     /* It's not there */
204     return NULL;
205 }
206
207 /* -----------------------------------------------------------------------------
208  * We allocate the hashlist cells in large chunks to cut down on malloc
209  * overhead.  Although we keep a free list of hashlist cells, we make
210  * no effort to actually return the space to the malloc arena.
211  * -------------------------------------------------------------------------- */
212
213 static HashList *freeList = NULL;
214
215 static HashList *
216 allocHashList(void)
217 {
218     HashList *hl, *p;
219
220     if ((hl = freeList) != NULL) {
221         freeList = hl->next;
222     } else {
223         hl = stgMallocBytes(HCHUNK * sizeof(HashList), "allocHashList");
224
225         freeList = hl + 1;
226         for (p = freeList; p < hl + HCHUNK - 1; p++)
227             p->next = p + 1;
228         p->next = NULL;
229     }
230     return hl;
231 }
232
233 static void
234 freeHashList(HashList *hl)
235 {
236     hl->next = freeList;
237     freeList = hl;
238 }
239
240 void
241 insertHashTable(HashTable *table, StgWord key, void *data)
242 {
243     int bucket;
244     int segment;
245     int index;
246     HashList *hl;
247
248     // Disable this assert; sometimes it's useful to be able to
249     // overwrite entries in the hash table.
250     // ASSERT(lookupHashTable(table, key) == NULL);
251
252     /* When the average load gets too high, we expand the table */
253     if (++table->kcount >= HLOAD * table->bcount)
254         expand(table);
255
256     bucket = table->hash(table, key);
257     segment = bucket / HSEGSIZE;
258     index = bucket % HSEGSIZE;
259
260     hl = allocHashList();
261
262     hl->key = key;
263     hl->data = data;
264     hl->next = table->dir[segment][index];
265     table->dir[segment][index] = hl;
266
267 }
268
269 void *
270 removeHashTable(HashTable *table, StgWord key, void *data)
271 {
272     int bucket;
273     int segment;
274     int index;
275     HashList *hl;
276     HashList *prev = NULL;
277
278     bucket = table->hash(table, key);
279     segment = bucket / HSEGSIZE;
280     index = bucket % HSEGSIZE;
281
282     for (hl = table->dir[segment][index]; hl != NULL; hl = hl->next) {
283         if (table->compare(hl->key,key) && (data == NULL || hl->data == data)) {
284             if (prev == NULL)
285                 table->dir[segment][index] = hl->next;
286             else
287                 prev->next = hl->next;
288             freeHashList(hl);
289             table->kcount--;
290             return hl->data;
291         }
292         prev = hl;
293     }
294
295     /* It's not there */
296     ASSERT(data == NULL);
297     return NULL;
298 }
299
300 /* -----------------------------------------------------------------------------
301  * When we free a hash table, we are also good enough to free the
302  * data part of each (key, data) pair, as long as our caller can tell
303  * us how to do it.
304  * -------------------------------------------------------------------------- */
305
306 void
307 freeHashTable(HashTable *table, void (*freeDataFun)(void *) )
308 {
309     long segment;
310     long index;
311     HashList *hl;
312     HashList *next;
313
314     /* The last bucket with something in it is table->max + table->split - 1 */
315     segment = (table->max + table->split - 1) / HSEGSIZE;
316     index = (table->max + table->split - 1) % HSEGSIZE;
317
318     while (segment >= 0) {
319         while (index >= 0) {
320             for (hl = table->dir[segment][index]; hl != NULL; hl = next) {
321                 next = hl->next;
322                 if (freeDataFun != NULL)
323                     (*freeDataFun)(hl->data);
324                 freeHashList(hl);
325             }
326             index--;
327         }
328         stgFree(table->dir[segment]);
329         segment--;
330         index = HSEGSIZE - 1;
331     }
332     stgFree(table);
333 }
334
335 /* -----------------------------------------------------------------------------
336  * When we initialize a hash table, we set up the first segment as well,
337  * initializing all of the first segment's hash buckets to NULL.
338  * -------------------------------------------------------------------------- */
339
340 static HashTable *
341 allocHashTable_(HashFunction *hash, CompareFunction *compare)
342 {
343     HashTable *table;
344     HashList **hb;
345
346     table = stgMallocBytes(sizeof(HashTable),"allocHashTable");
347
348     allocSegment(table, 0);
349
350     for (hb = table->dir[0]; hb < table->dir[0] + HSEGSIZE; hb++)
351         *hb = NULL;
352
353     table->split = 0;
354     table->max = HSEGSIZE;
355     table->mask1 = HSEGSIZE - 1;
356     table->mask2 = 2 * HSEGSIZE - 1;
357     table->kcount = 0;
358     table->bcount = HSEGSIZE;
359     table->hash = hash;
360     table->compare = compare;
361
362     return table;
363 }
364
365 HashTable *
366 allocHashTable(void)
367 {
368     return allocHashTable_(hashWord, compareWord);
369 }
370
371 HashTable *
372 allocStrHashTable(void)
373 {
374     return allocHashTable_((HashFunction *)hashStr, 
375                            (CompareFunction *)compareStr);
376 }