Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/boost_1_33_1/tools/build/jam_src/hash.c @ 12

Last change on this file since 12 was 12, checked in by landauf, 17 years ago

added boost

File size: 7.2 KB
Line 
1/*
2 * Copyright 1993, 1995 Christopher Seiwald.
3 *
4 * This file is part of Jam - see jam.c for Copyright information.
5 */
6
7# include "jam.h"
8# include "hash.h"
9# include <assert.h>
10
11/*
12 * hash.c - simple in-memory hashing routines
13 *
14 * External routines:
15 *
16 *     hashinit() - initialize a hash table, returning a handle
17 *     hashitem() - find a record in the table, and optionally enter a new one
18 *     hashdone() - free a hash table, given its handle
19 *
20 * Internal routines:
21 *
22 *     hashrehash() - resize and rebuild hp->tab, the hash table
23 *
24 * 4/29/93 - ensure ITEM's are aligned
25 */
26
27char    *hashsccssid="@(#)hash.c        1.14  ()  6/20/88";
28
29/* Header attached to all data items entered into a hash table. */
30
31struct hashhdr {
32        struct item *next;
33        unsigned int keyval;                    /* for quick comparisons */
34} ;
35
36/* This structure overlays the one handed to hashenter(). */
37/* It's actual size is given to hashinit(). */
38
39struct hashdata {
40        char    *key;
41        /* rest of user data */
42} ;
43
44typedef struct item {
45        struct hashhdr hdr;
46        struct hashdata data;
47} ITEM ;
48
49# define MAX_LISTS 32
50
51struct hash
52{
53        /*
54         * the hash table, just an array of item pointers
55         */
56        struct {
57                int nel;
58                ITEM **base;
59        } tab;
60
61        int bloat;      /* tab.nel / items.nel */
62        int inel;       /* initial number of elements */
63
64        /*
65         * the array of records, maintained by these routines
66         * essentially a microallocator
67         */ 
68        struct {
69                int more;       /* how many more ITEMs fit in lists[ list ] */
70        ITEM *free; /* free list of items */
71                char *next;     /* where to put more ITEMs in lists[ list ] */
72                int datalen;    /* length of records in this hash table */
73                int size;       /* sizeof( ITEM ) + aligned datalen */
74                int nel;        /* total ITEMs held by all lists[] */
75                int list;       /* index into lists[] */
76
77                struct {
78                        int nel;        /* total ITEMs held by this list */
79                        char *base;     /* base of ITEMs array */
80                } lists[ MAX_LISTS ];
81        } items;
82
83        char *name;     /* just for hashstats() */
84} ;
85
86static void hashrehash( struct hash *hp );
87static void hashstat( struct hash *hp );
88
89/*
90 * hash_free() - remove the given item from the table if it's there.
91 * Returns 1 if found, 0 otherwise.
92 *
93 * NOTE: 2nd argument is HASHDATA*, not HASHDATA** as elsewhere.
94 */
95int
96hash_free(
97        register struct hash *hp,
98        HASHDATA *data)
99{
100        ITEM **prev;
101        register ITEM **i;
102        unsigned char *b = (unsigned char*)data->key;
103        unsigned int keyval;
104
105        keyval = *b;
106
107        while( *b )
108                keyval = keyval * 2147059363 + *b++;
109
110    prev = hp->tab.base + ( keyval % hp->tab.nel );
111        while(*prev )
112    {
113        register ITEM* i = *prev;
114            if( keyval == i->hdr.keyval && 
115            !strcmp( i->data.key, data->key ) )
116        {
117            /* unlink the record from the hash chain */
118            *prev = i->hdr.next;
119            /* link it into the freelist */
120            i->hdr.next = hp->items.free;
121            hp->items.free = i;
122            /* mark it free so we skip it during enumeration */
123            i->data.key = 0;
124            /* we have another item */
125            hp->items.more++;
126            return 1;
127        }
128        prev = &i->hdr.next;
129    }
130    return 0;
131}
132
133/*
134 * hashitem() - find a record in the table, and optionally enter a new one
135 */
136
137int
138hashitem(
139        register struct hash *hp,
140        HASHDATA **data,
141        int enter )
142{
143        ITEM **base;
144        register ITEM *i;
145        unsigned char *b = (unsigned char*)(*data)->key;
146        unsigned int keyval;
147
148        if( enter && !hp->items.more )
149            hashrehash( hp );
150
151        if( !enter && !hp->items.nel )
152            return 0;
153
154        keyval = *b;
155
156        while( *b )
157                keyval = keyval * 2147059363 + *b++;
158
159        base = hp->tab.base + ( keyval % hp->tab.nel );
160
161        for( i = *base; i; i = i->hdr.next )
162            if( keyval == i->hdr.keyval && 
163                !strcmp( i->data.key, (*data)->key ) )
164        {
165                *data = &i->data;
166                return !0;
167        }
168
169        if( enter ) 
170        {
171        /* try to grab one from the free list */
172        if ( hp->items.free )
173        {
174            i = hp->items.free;
175            hp->items.free = i->hdr.next;
176            assert( i->data.key == 0 );
177        }
178        else
179        {
180            i = (ITEM *)hp->items.next;
181            hp->items.next += hp->items.size;
182        }
183                hp->items.more--;
184                memcpy( (char *)&i->data, (char *)*data, hp->items.datalen );
185                i->hdr.keyval = keyval;
186                i->hdr.next = *base;
187                *base = i;
188                *data = &i->data;
189        }
190
191        return 0;
192}
193
194/*
195 * hashrehash() - resize and rebuild hp->tab, the hash table
196 */
197
198static void hashrehash( register struct hash *hp )
199{
200        int i = ++hp->items.list;
201
202        hp->items.more = i ? 2 * hp->items.nel : hp->inel;
203        hp->items.next = (char *)malloc( hp->items.more * hp->items.size );
204    hp->items.free = 0;
205   
206        hp->items.lists[i].nel = hp->items.more;
207        hp->items.lists[i].base = hp->items.next;
208        hp->items.nel += hp->items.more;
209
210        if( hp->tab.base )
211                free( (char *)hp->tab.base );
212
213        hp->tab.nel = hp->items.nel * hp->bloat;
214        hp->tab.base = (ITEM **)malloc( hp->tab.nel * sizeof(ITEM **) );
215
216        memset( (char *)hp->tab.base, '\0', hp->tab.nel * sizeof( ITEM * ) );
217
218        for( i = 0; i < hp->items.list; i++ )
219        {
220                int nel = hp->items.lists[i].nel;
221                char *next = hp->items.lists[i].base;
222
223                for( ; nel--; next += hp->items.size )
224                {
225                        register ITEM *i = (ITEM *)next;
226                        ITEM **ip = hp->tab.base + i->hdr.keyval % hp->tab.nel;
227            /* code currently assumes rehashing only when there are no free items */
228            assert( i->data.key != 0 ); 
229           
230                        i->hdr.next = *ip;
231                        *ip = i;
232                }
233        }
234}
235
236void hashenumerate( struct hash *hp, void (*f)(void*,void*), void* data )
237{
238    int i;
239    for( i = 0; i <= hp->items.list; i++ )
240    {
241        char *next = hp->items.lists[i].base;
242        int nel = hp->items.lists[i].nel;
243        if ( i == hp->items.list )
244            nel -= hp->items.more;
245
246        for( ; nel--; next += hp->items.size )
247        {
248            register ITEM *i = (ITEM *)next;
249           
250            if ( i->data.key != 0 ) /* don't enumerate freed items */
251                f(&i->data, data);
252        }
253    }
254}
255
256/* --- */
257
258# define ALIGNED(x) ( ( x + sizeof( ITEM ) - 1 ) & ~( sizeof( ITEM ) - 1 ) )
259
260/*
261 * hashinit() - initialize a hash table, returning a handle
262 */
263
264struct hash *
265hashinit( 
266        int datalen,
267        char *name )
268{
269        struct hash *hp = (struct hash *)malloc( sizeof( *hp ) );
270
271        hp->bloat = 3;
272        hp->tab.nel = 0;
273        hp->tab.base = (ITEM **)0;
274        hp->items.more = 0;
275    hp->items.free = 0;
276        hp->items.datalen = datalen;
277        hp->items.size = sizeof( struct hashhdr ) + ALIGNED( datalen );
278        hp->items.list = -1;
279        hp->items.nel = 0;
280        hp->inel = 11;
281        hp->name = name;
282
283        return hp;
284}
285
286/*
287 * hashdone() - free a hash table, given its handle
288 */
289
290void
291hashdone( struct hash *hp )
292{
293        int i;
294
295        if( !hp )
296            return;
297
298        if( DEBUG_MEM )
299            hashstat( hp );
300
301        if( hp->tab.base )
302                free( (char *)hp->tab.base );
303        for( i = 0; i <= hp->items.list; i++ )
304                free( hp->items.lists[i].base );
305        free( (char *)hp );
306}
307
308/* ---- */
309
310static void
311hashstat( struct hash *hp )
312{
313        ITEM **tab = hp->tab.base;
314        int nel = hp->tab.nel;
315        int count = 0;
316        int sets = 0;
317        int run = ( tab[ nel - 1 ] != (ITEM *)0 );
318        int i, here;
319
320        for( i = nel; i > 0; i-- )
321        {
322                if( here = ( *tab++ != (ITEM *)0 ) )
323                        count++;
324                if( here && !run )
325                        sets++;
326                run = here;
327        }
328
329        printf( "%s table: %d+%d+%d (%dK+%dK) items+table+hash, %f density\n",
330                hp->name, 
331                count, 
332                hp->items.nel,
333                hp->tab.nel,
334                hp->items.nel * hp->items.size / 1024,
335                hp->tab.nel * sizeof( ITEM ** ) / 1024,
336                (float)count / (float)sets );
337}
Note: See TracBrowser for help on using the repository browser.