source: trunk/src/binutils/gas/hash.c@ 1036

Last change on this file since 1036 was 610, checked in by bird, 22 years ago

This commit was generated by cvs2svn to compensate for changes in r609,
which included commits to RCS files with non-trunk default branches.

  • Property cvs2svn:cvs-rev set to 1.1.1.2
  • Property svn:eol-style set to native
  • Property svn:executable set to *
File size: 13.4 KB
Line 
1/* hash.c -- gas hash table code
2 Copyright 1987, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1998, 1999,
3 2000, 2001, 2002
4 Free Software Foundation, Inc.
5
6 This file is part of GAS, the GNU Assembler.
7
8 GAS is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2, or (at your option)
11 any later version.
12
13 GAS is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with GAS; see the file COPYING. If not, write to the Free
20 Software Foundation, 59 Temple Place - Suite 330, Boston, MA
21 02111-1307, USA. */
22
23/* This version of the hash table code is a wholescale replacement of
24 the old hash table code, which was fairly bad. This is based on
25 the hash table code in BFD, but optimized slightly for the
26 asssembler. The assembler does not need to derive structures that
27 are stored in the hash table. Instead, it always stores a pointer.
28 The assembler uses the hash table mostly to store symbols, and we
29 don't need to confuse the symbol structure with a hash table
30 structure. */
31
32#include "as.h"
33#include "safe-ctype.h"
34#include "obstack.h"
35
36/* The default number of entries to use when creating a hash table. */
37
38#define DEFAULT_SIZE (4051)
39
40/* An entry in a hash table. */
41
42struct hash_entry {
43 /* Next entry for this hash code. */
44 struct hash_entry *next;
45 /* String being hashed. */
46 const char *string;
47 /* Hash code. This is the full hash code, not the index into the
48 table. */
49 unsigned long hash;
50 /* Pointer being stored in the hash table. */
51 PTR data;
52};
53
54/* A hash table. */
55
56struct hash_control {
57 /* The hash array. */
58 struct hash_entry **table;
59 /* The number of slots in the hash table. */
60 unsigned int size;
61 /* An obstack for this hash table. */
62 struct obstack memory;
63
64#ifdef HASH_STATISTICS
65 /* Statistics. */
66 unsigned long lookups;
67 unsigned long hash_compares;
68 unsigned long string_compares;
69 unsigned long insertions;
70 unsigned long replacements;
71 unsigned long deletions;
72#endif /* HASH_STATISTICS */
73};
74
75/* Create a hash table. This return a control block. */
76
77struct hash_control *
78hash_new ()
79{
80 unsigned int size;
81 struct hash_control *ret;
82 unsigned int alloc;
83
84 size = DEFAULT_SIZE;
85
86 ret = (struct hash_control *) xmalloc (sizeof *ret);
87 obstack_begin (&ret->memory, chunksize);
88 alloc = size * sizeof (struct hash_entry *);
89 ret->table = (struct hash_entry **) obstack_alloc (&ret->memory, alloc);
90 memset (ret->table, 0, alloc);
91 ret->size = size;
92
93#ifdef HASH_STATISTICS
94 ret->lookups = 0;
95 ret->hash_compares = 0;
96 ret->string_compares = 0;
97 ret->insertions = 0;
98 ret->replacements = 0;
99 ret->deletions = 0;
100#endif
101
102 return ret;
103}
104
105/* Delete a hash table, freeing all allocated memory. */
106
107void
108hash_die (table)
109 struct hash_control *table;
110{
111 obstack_free (&table->memory, 0);
112 free (table);
113}
114
115/* Look up a string in a hash table. This returns a pointer to the
116 hash_entry, or NULL if the string is not in the table. If PLIST is
117 not NULL, this sets *PLIST to point to the start of the list which
118 would hold this hash entry. If PHASH is not NULL, this sets *PHASH
119 to the hash code for KEY.
120
121 Each time we look up a string, we move it to the start of the list
122 for its hash code, to take advantage of referential locality. */
123
124static struct hash_entry *hash_lookup PARAMS ((struct hash_control *,
125 const char *,
126 struct hash_entry ***,
127 unsigned long *));
128
129static struct hash_entry *
130hash_lookup (table, key, plist, phash)
131 struct hash_control *table;
132 const char *key;
133 struct hash_entry ***plist;
134 unsigned long *phash;
135{
136 register unsigned long hash;
137 unsigned int len;
138 register const unsigned char *s;
139 register unsigned int c;
140 unsigned int index;
141 struct hash_entry **list;
142 struct hash_entry *p;
143 struct hash_entry *prev;
144
145#ifdef HASH_STATISTICS
146 ++table->lookups;
147#endif
148
149 hash = 0;
150 len = 0;
151 s = (const unsigned char *) key;
152 while ((c = *s++) != '\0')
153 {
154 hash += c + (c << 17);
155 hash ^= hash >> 2;
156 ++len;
157 }
158 hash += len + (len << 17);
159 hash ^= hash >> 2;
160
161 if (phash != NULL)
162 *phash = hash;
163
164 index = hash % table->size;
165 list = table->table + index;
166
167 if (plist != NULL)
168 *plist = list;
169
170 prev = NULL;
171 for (p = *list; p != NULL; p = p->next)
172 {
173#ifdef HASH_STATISTICS
174 ++table->hash_compares;
175#endif
176
177 if (p->hash == hash)
178 {
179#ifdef HASH_STATISTICS
180 ++table->string_compares;
181#endif
182
183 if (strcmp (p->string, key) == 0)
184 {
185 if (prev != NULL)
186 {
187 prev->next = p->next;
188 p->next = *list;
189 *list = p;
190 }
191
192 return p;
193 }
194 }
195
196 prev = p;
197 }
198
199 return NULL;
200}
201
202/* Insert an entry into a hash table. This returns NULL on success.
203 On error, it returns a printable string indicating the error. It
204 is considered to be an error if the entry already exists in the
205 hash table. */
206
207const char *
208hash_insert (table, key, value)
209 struct hash_control *table;
210 const char *key;
211 PTR value;
212{
213 struct hash_entry *p;
214 struct hash_entry **list;
215 unsigned long hash;
216
217 p = hash_lookup (table, key, &list, &hash);
218 if (p != NULL)
219 return "exists";
220
221#ifdef HASH_STATISTICS
222 ++table->insertions;
223#endif
224
225 p = (struct hash_entry *) obstack_alloc (&table->memory, sizeof (*p));
226 p->string = key;
227 p->hash = hash;
228 p->data = value;
229
230 p->next = *list;
231 *list = p;
232
233 return NULL;
234}
235
236/* Insert or replace an entry in a hash table. This returns NULL on
237 success. On error, it returns a printable string indicating the
238 error. If an entry already exists, its value is replaced. */
239
240const char *
241hash_jam (table, key, value)
242 struct hash_control *table;
243 const char *key;
244 PTR value;
245{
246 struct hash_entry *p;
247 struct hash_entry **list;
248 unsigned long hash;
249
250 p = hash_lookup (table, key, &list, &hash);
251 if (p != NULL)
252 {
253#ifdef HASH_STATISTICS
254 ++table->replacements;
255#endif
256
257 p->data = value;
258 }
259 else
260 {
261#ifdef HASH_STATISTICS
262 ++table->insertions;
263#endif
264
265 p = (struct hash_entry *) obstack_alloc (&table->memory, sizeof (*p));
266 p->string = key;
267 p->hash = hash;
268 p->data = value;
269
270 p->next = *list;
271 *list = p;
272 }
273
274 return NULL;
275}
276
277/* Replace an existing entry in a hash table. This returns the old
278 value stored for the entry. If the entry is not found in the hash
279 table, this does nothing and returns NULL. */
280
281PTR
282hash_replace (table, key, value)
283 struct hash_control *table;
284 const char *key;
285 PTR value;
286{
287 struct hash_entry *p;
288 PTR ret;
289
290 p = hash_lookup (table, key, NULL, NULL);
291 if (p == NULL)
292 return NULL;
293
294#ifdef HASH_STATISTICS
295 ++table->replacements;
296#endif
297
298 ret = p->data;
299
300 p->data = value;
301
302 return ret;
303}
304
305/* Find an entry in a hash table, returning its value. Returns NULL
306 if the entry is not found. */
307
308PTR
309hash_find (table, key)
310 struct hash_control *table;
311 const char *key;
312{
313 struct hash_entry *p;
314
315 p = hash_lookup (table, key, NULL, NULL);
316 if (p == NULL)
317 return NULL;
318
319 return p->data;
320}
321
322/* Delete an entry from a hash table. This returns the value stored
323 for that entry, or NULL if there is no such entry. */
324
325PTR
326hash_delete (table, key)
327 struct hash_control *table;
328 const char *key;
329{
330 struct hash_entry *p;
331 struct hash_entry **list;
332
333 p = hash_lookup (table, key, &list, NULL);
334 if (p == NULL)
335 return NULL;
336
337 if (p != *list)
338 abort ();
339
340#ifdef HASH_STATISTICS
341 ++table->deletions;
342#endif
343
344 *list = p->next;
345
346 /* Note that we never reclaim the memory for this entry. If gas
347 ever starts deleting hash table entries in a big way, this will
348 have to change. */
349
350 return p->data;
351}
352
353/* Traverse a hash table. Call the function on every entry in the
354 hash table. */
355
356void
357hash_traverse (table, pfn)
358 struct hash_control *table;
359 void (*pfn) PARAMS ((const char *key, PTR value));
360{
361 unsigned int i;
362
363 for (i = 0; i < table->size; ++i)
364 {
365 struct hash_entry *p;
366
367 for (p = table->table[i]; p != NULL; p = p->next)
368 (*pfn) (p->string, p->data);
369 }
370}
371
372/* Print hash table statistics on the specified file. NAME is the
373 name of the hash table, used for printing a header. */
374
375void
376hash_print_statistics (f, name, table)
377 FILE *f ATTRIBUTE_UNUSED;
378 const char *name ATTRIBUTE_UNUSED;
379 struct hash_control *table ATTRIBUTE_UNUSED;
380{
381#ifdef HASH_STATISTICS
382 unsigned int i;
383 unsigned long total;
384 unsigned long empty;
385
386 fprintf (f, "%s hash statistics:\n", name);
387 fprintf (f, "\t%lu lookups\n", table->lookups);
388 fprintf (f, "\t%lu hash comparisons\n", table->hash_compares);
389 fprintf (f, "\t%lu string comparisons\n", table->string_compares);
390 fprintf (f, "\t%lu insertions\n", table->insertions);
391 fprintf (f, "\t%lu replacements\n", table->replacements);
392 fprintf (f, "\t%lu deletions\n", table->deletions);
393
394 total = 0;
395 empty = 0;
396 for (i = 0; i < table->size; ++i)
397 {
398 struct hash_entry *p;
399
400 if (table->table[i] == NULL)
401 ++empty;
402 else
403 {
404 for (p = table->table[i]; p != NULL; p = p->next)
405 ++total;
406 }
407 }
408
409 fprintf (f, "\t%g average chain length\n", (double) total / table->size);
410 fprintf (f, "\t%lu empty slots\n", empty);
411#endif
412}
413
414
415#ifdef TEST
416
417/* This test program is left over from the old hash table code. */
418
419/* Number of hash tables to maintain (at once) in any testing. */
420#define TABLES (6)
421
422/* We can have 12 statistics. */
423#define STATBUFSIZE (12)
424
425/* Display statistics here. */
426int statbuf[STATBUFSIZE];
427
428/* Human farts here. */
429char answer[100];
430
431/* We test many hash tables at once. */
432char *hashtable[TABLES];
433
434/* Points to curent hash_control. */
435char *h;
436char **pp;
437char *p;
438char *name;
439char *value;
440int size;
441int used;
442char command;
443
444/* Number 0:TABLES-1 of current hashed symbol table. */
445int number;
446
447int
448main ()
449{
450 void applicatee ();
451 void destroy ();
452 char *what ();
453 int *ip;
454
455 number = 0;
456 h = 0;
457 printf ("type h <RETURN> for help\n");
458 for (;;)
459 {
460 printf ("hash_test command: ");
461 gets (answer);
462 command = answer[0];
463 command = TOLOWER (command); /* Ecch! */
464 switch (command)
465 {
466 case '#':
467 printf ("old hash table #=%d.\n", number);
468 whattable ();
469 break;
470 case '?':
471 for (pp = hashtable; pp < hashtable + TABLES; pp++)
472 {
473 printf ("address of hash table #%d control block is %xx\n",
474 pp - hashtable, *pp);
475 }
476 break;
477 case 'a':
478 hash_traverse (h, applicatee);
479 break;
480 case 'd':
481 hash_traverse (h, destroy);
482 hash_die (h);
483 break;
484 case 'f':
485 p = hash_find (h, name = what ("symbol"));
486 printf ("value of \"%s\" is \"%s\"\n", name, p ? p : "NOT-PRESENT");
487 break;
488 case 'h':
489 printf ("# show old, select new default hash table number\n");
490 printf ("? display all hashtable control block addresses\n");
491 printf ("a apply a simple display-er to each symbol in table\n");
492 printf ("d die: destroy hashtable\n");
493 printf ("f find value of nominated symbol\n");
494 printf ("h this help\n");
495 printf ("i insert value into symbol\n");
496 printf ("j jam value into symbol\n");
497 printf ("n new hashtable\n");
498 printf ("r replace a value with another\n");
499 printf ("s say what %% of table is used\n");
500 printf ("q exit this program\n");
501 printf ("x delete a symbol from table, report its value\n");
502 break;
503 case 'i':
504 p = hash_insert (h, name = what ("symbol"), value = what ("value"));
505 if (p)
506 {
507 printf ("symbol=\"%s\" value=\"%s\" error=%s\n", name, value,
508 p);
509 }
510 break;
511 case 'j':
512 p = hash_jam (h, name = what ("symbol"), value = what ("value"));
513 if (p)
514 {
515 printf ("symbol=\"%s\" value=\"%s\" error=%s\n", name, value, p);
516 }
517 break;
518 case 'n':
519 h = hashtable[number] = (char *) hash_new ();
520 break;
521 case 'q':
522 exit (EXIT_SUCCESS);
523 case 'r':
524 p = hash_replace (h, name = what ("symbol"), value = what ("value"));
525 printf ("old value was \"%s\"\n", p ? p : "{}");
526 break;
527 case 's':
528 hash_say (h, statbuf, STATBUFSIZE);
529 for (ip = statbuf; ip < statbuf + STATBUFSIZE; ip++)
530 {
531 printf ("%d ", *ip);
532 }
533 printf ("\n");
534 break;
535 case 'x':
536 p = hash_delete (h, name = what ("symbol"));
537 printf ("old value was \"%s\"\n", p ? p : "{}");
538 break;
539 default:
540 printf ("I can't understand command \"%c\"\n", command);
541 break;
542 }
543 }
544}
545
546char *
547what (description)
548 char *description;
549{
550 printf (" %s : ", description);
551 gets (answer);
552 return xstrdup (answer);
553}
554
555void
556destroy (string, value)
557 char *string;
558 char *value;
559{
560 free (string);
561 free (value);
562}
563
564void
565applicatee (string, value)
566 char *string;
567 char *value;
568{
569 printf ("%.20s-%.20s\n", string, value);
570}
571
572/* Determine number: what hash table to use.
573 Also determine h: points to hash_control. */
574
575void
576whattable ()
577{
578 for (;;)
579 {
580 printf (" what hash table (%d:%d) ? ", 0, TABLES - 1);
581 gets (answer);
582 sscanf (answer, "%d", &number);
583 if (number >= 0 && number < TABLES)
584 {
585 h = hashtable[number];
586 if (!h)
587 {
588 printf ("warning: current hash-table-#%d. has no hash-control\n", number);
589 }
590 return;
591 }
592 else
593 {
594 printf ("invalid hash table number: %d\n", number);
595 }
596 }
597}
598
599#endif /* TEST */
Note: See TracBrowser for help on using the repository browser.