]>
Commit | Line | Data |
---|---|---|
fecd2382 | 1 | /* hash.c - hash table lookup strings - |
95ac738e KR |
2 | Copyright (C) 1987, 1990, 1991, 1992 Free Software Foundation, Inc. |
3 | ||
a39116f1 | 4 | This file is part of GAS, the GNU Assembler. |
95ac738e | 5 | |
a39116f1 RP |
6 | GAS is free software; you can redistribute it and/or modify |
7 | it under the terms of the GNU General Public License as published by | |
8 | the Free Software Foundation; either version 2, or (at your option) | |
9 | any later version. | |
95ac738e | 10 | |
a39116f1 RP |
11 | GAS is distributed in the hope that it will be useful, |
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | GNU General Public License for more details. | |
95ac738e | 15 | |
a39116f1 RP |
16 | You should have received a copy of the GNU General Public License |
17 | along with GAS; see the file COPYING. If not, write to | |
18 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ | |
fecd2382 RP |
19 | |
20 | /* | |
21 | * BUGS, GRIPES, APOLOGIA etc. | |
22 | * | |
23 | * A typical user doesn't need ALL this: I intend to make a library out | |
24 | * of it one day - Dean Elsner. | |
25 | * Also, I want to change the definition of a symbol to (address,length) | |
26 | * so I can put arbitrary binary in the names stored. [see hsh.c for that] | |
27 | * | |
28 | * This slime is common coupled inside the module. Com-coupling (and other | |
29 | * vandalism) was done to speed running time. The interfaces at the | |
30 | * module's edges are adequately clean. | |
31 | * | |
32 | * There is no way to (a) run a test script through this heap and (b) | |
33 | * compare results with previous scripts, to see if we have broken any | |
34 | * code. Use GNU (f)utilities to do this. A few commands assist test. | |
35 | * The testing is awkward: it tries to be both batch & interactive. | |
36 | * For now, interactive rules! | |
37 | */ | |
38 | \f | |
39 | /* | |
40 | * The idea is to implement a symbol table. A test jig is here. | |
41 | * Symbols are arbitrary strings; they can't contain '\0'. | |
42 | * [See hsh.c for a more general symbol flavour.] | |
43 | * Each symbol is associated with a char*, which can point to anything | |
44 | * you want, allowing an arbitrary property list for each symbol. | |
45 | * | |
46 | * The basic operations are: | |
47 | * | |
48 | * new creates symbol table, returns handle | |
49 | * find (symbol) returns char* | |
50 | * insert (symbol,char*) error if symbol already in table | |
51 | * delete (symbol) returns char* if symbol was in table | |
52 | * apply so you can delete all symbols before die() | |
53 | * die destroy symbol table (free up memory) | |
54 | * | |
55 | * Supplementary functions include: | |
56 | * | |
57 | * say how big? what % full? | |
58 | * replace (symbol,newval) report previous value | |
59 | * jam (symbol,value) assert symbol:=value | |
60 | * | |
61 | * You, the caller, have control over errors: this just reports them. | |
62 | * | |
63 | * This package requires malloc(), free(). | |
64 | * Malloc(size) returns NULL or address of char[size]. | |
65 | * Free(address) frees same. | |
66 | */ | |
67 | \f | |
68 | /* | |
69 | * The code and its structures are re-enterent. | |
95ac738e | 70 | * |
fecd2382 | 71 | * Before you do anything else, you must call hash_new() which will |
95ac738e KR |
72 | * return the address of a hash-table-control-block. You then use |
73 | * this address as a handle of the symbol table by passing it to all | |
74 | * the other hash_...() functions. The only approved way to recover | |
75 | * the memory used by the symbol table is to call hash_die() with the | |
76 | * handle of the symbol table. | |
fecd2382 RP |
77 | * |
78 | * Before you call hash_die() you normally delete anything pointed to | |
79 | * by individual symbols. After hash_die() you can't use that symbol | |
80 | * table again. | |
81 | * | |
82 | * The char* you associate with a symbol may not be NULL (0) because | |
83 | * NULL is returned whenever a symbol is not in the table. Any other | |
84 | * value is OK, except DELETED, #defined below. | |
85 | * | |
86 | * When you supply a symbol string for insertion, YOU MUST PRESERVE THE | |
87 | * STRING until that symbol is deleted from the table. The reason is that | |
88 | * only the address you supply, NOT the symbol string itself, is stored | |
89 | * in the symbol table. | |
90 | * | |
91 | * You may delete and add symbols arbitrarily. | |
92 | * Any or all symbols may have the same 'value' (char *). In fact, these | |
93 | * routines don't do anything with your symbol values. | |
94 | * | |
95 | * You have no right to know where the symbol:char* mapping is stored, | |
96 | * because it moves around in memory; also because we may change how it | |
97 | * works and we don't want to break your code do we? However the handle | |
98 | * (address of struct hash_control) is never changed in | |
99 | * the life of the symbol table. | |
100 | * | |
101 | * What you CAN find out about a symbol table is: | |
102 | * how many slots are in the hash table? | |
103 | * how many slots are filled with symbols? | |
104 | * (total hashes,collisions) for (reads,writes) (*) | |
105 | * All of the above values vary in time. | |
106 | * (*) some of these numbers will not be meaningful if we change the | |
95ac738e | 107 | * internals. */ |
fecd2382 RP |
108 | \f |
109 | /* | |
110 | * I N T E R N A L | |
111 | * | |
112 | * Hash table is an array of hash_entries; each entry is a pointer to a | |
113 | * a string and a user-supplied value 1 char* wide. | |
114 | * | |
115 | * The array always has 2 ** n elements, n>0, n integer. | |
116 | * There is also a 'wall' entry after the array, which is always empty | |
117 | * and acts as a sentinel to stop running off the end of the array. | |
118 | * When the array gets too full, we create a new array twice as large | |
119 | * and re-hash the symbols into the new array, then forget the old array. | |
120 | * (Of course, we copy the values into the new array before we junk the | |
121 | * old array!) | |
122 | * | |
123 | */ | |
124 | ||
125 | #include <stdio.h> | |
126 | ||
127 | #ifndef FALSE | |
128 | #define FALSE (0) | |
129 | #define TRUE (!FALSE) | |
130 | #endif /* no FALSE yet */ | |
131 | ||
132 | #include <ctype.h> | |
133 | #define min(a, b) ((a) < (b) ? (a) : (b)) | |
134 | ||
135 | #include "as.h" | |
136 | ||
137 | #define error as_fatal | |
138 | ||
95ac738e KR |
139 | #define DELETED ((PTR)1) /* guarenteed invalid address */ |
140 | #define START_POWER (11) /* power of two: size of new hash table */ | |
141 | ||
142 | /* TRUE if a symbol is in entry @ ptr. */ | |
fecd2382 | 143 | #define islive(ptr) (ptr->hash_string && ptr->hash_string!=DELETED) |
fecd2382 | 144 | |
95ac738e KR |
145 | /* Number of slots in hash table. The wall does not count here. |
146 | We expect this is always a power of 2. */ | |
147 | #define STAT_SIZE (0) | |
fecd2382 | 148 | #define STAT_ACCESS (1) /* number of hash_ask()s */ |
95ac738e KR |
149 | #define STAT__READ (0) /* reading */ |
150 | #define STAT__WRITE (1) /* writing */ | |
151 | /* Number of collisions (total). This may exceed STAT_ACCESS if we | |
152 | have lots of collisions/access. */ | |
153 | #define STAT_COLLIDE (3) | |
fecd2382 RP |
154 | #define STAT_USED (5) /* slots used right now */ |
155 | #define STATLENGTH (6) /* size of statistics block */ | |
156 | #if STATLENGTH != HASH_STATLENGTH | |
157 | Panic! Please make #include "stat.h" agree with previous definitions! | |
158 | #endif | |
95ac738e KR |
159 | |
160 | /* #define SUSPECT to do runtime checks */ | |
161 | /* #define TEST to be a test jig for hash...() */ | |
162 | ||
163 | #ifdef TEST | |
164 | /* TEST: use smaller hash table */ | |
fecd2382 RP |
165 | #undef START_POWER |
166 | #define START_POWER (3) | |
167 | #undef START_SIZE | |
168 | #define START_SIZE (8) | |
169 | #undef START_FULL | |
170 | #define START_FULL (4) | |
171 | #endif | |
172 | \f | |
173 | /*------------------ plan ---------------------------------- i = internal | |
95ac738e | 174 | |
a39116f1 RP |
175 | struct hash_control * c; |
176 | struct hash_entry * e; i | |
177 | int b[z]; buffer for statistics | |
178 | z size of b | |
179 | char * s; symbol string (address) [ key ] | |
180 | char * v; value string (address) [datum] | |
181 | boolean f; TRUE if we found s in hash table i | |
95ac738e | 182 | char * t; error string; 0 means OK |
a39116f1 | 183 | int a; access type [0...n) i |
95ac738e | 184 | |
a39116f1 | 185 | c=hash_new () create new hash_control |
95ac738e | 186 | |
a39116f1 RP |
187 | hash_die (c) destroy hash_control (and hash table) |
188 | table should be empty. | |
189 | doesn't check if table is empty. | |
190 | c has no meaning after this. | |
95ac738e | 191 | |
a39116f1 RP |
192 | hash_say (c,b,z) report statistics of hash_control. |
193 | also report number of available statistics. | |
95ac738e | 194 | |
a39116f1 RP |
195 | v=hash_delete (c,s) delete symbol, return old value if any. |
196 | ask() NULL means no old value. | |
197 | f | |
95ac738e | 198 | |
a39116f1 RP |
199 | v=hash_replace (c,s,v) replace old value of s with v. |
200 | ask() NULL means no old value: no table change. | |
201 | f | |
95ac738e | 202 | |
a39116f1 RP |
203 | t=hash_insert (c,s,v) insert (s,v) in c. |
204 | ask() return error string. | |
205 | f it is an error to insert if s is already | |
206 | in table. | |
207 | if any error, c is unchanged. | |
95ac738e | 208 | |
a39116f1 RP |
209 | t=hash_jam (c,s,v) assert that new value of s will be v. i |
210 | ask() it may decide to GROW the table. i | |
211 | f i | |
212 | grow() i | |
213 | t=hash_grow (c) grow the hash table. i | |
214 | jam() will invoke JAM. i | |
95ac738e | 215 | |
a39116f1 RP |
216 | ?=hash_apply (c,y) apply y() to every symbol in c. |
217 | y evtries visited in 'unspecified' order. | |
95ac738e | 218 | |
a39116f1 RP |
219 | v=hash_find (c,s) return value of s, or NULL if s not in c. |
220 | ask() | |
221 | f | |
95ac738e | 222 | |
a39116f1 RP |
223 | f,e=hash_ask() (c,s,a) return slot where s SHOULD live. i |
224 | code() maintain collision stats in c. i | |
95ac738e | 225 | |
a39116f1 RP |
226 | .=hash_code (c,s) compute hash-code for s, i |
227 | from parameters of c. i | |
95ac738e | 228 | |
a39116f1 | 229 | */ |
fecd2382 | 230 | \f |
95ac738e KR |
231 | /* Returned by hash_ask() to stop extra testing. hash_ask() wants to |
232 | return both a slot and a status. This is the status. TRUE: found | |
233 | symbol FALSE: absent: empty or deleted slot Also returned by | |
234 | hash_jam(). TRUE: we replaced a value FALSE: we inserted a value. */ | |
235 | static char hash_found; | |
236 | ||
237 | static struct hash_entry *hash_ask PARAMS ((struct hash_control *, | |
238 | const char *, int)); | |
239 | static int hash_code PARAMS ((struct hash_control *, const char *)); | |
240 | static const char *hash_grow PARAMS ((struct hash_control *)); | |
fecd2382 | 241 | \f |
95ac738e KR |
242 | /* Create a new hash table. Return NULL if failed; otherwise return handle |
243 | (address of struct hash). */ | |
fecd2382 | 244 | struct hash_control * |
95ac738e | 245 | hash_new () |
fecd2382 | 246 | { |
95ac738e KR |
247 | struct hash_control *retval; |
248 | struct hash_entry *room; /* points to hash table */ | |
249 | struct hash_entry *wall; | |
250 | struct hash_entry *entry; | |
251 | int *ip; /* scan stats block of struct hash_control */ | |
252 | int *nd; /* limit of stats block */ | |
253 | ||
254 | room = (struct hash_entry *) xmalloc (sizeof (struct hash_entry) | |
255 | /* +1 for the wall entry */ | |
256 | * ((1 << START_POWER) + 1)); | |
257 | retval = (struct hash_control *) xmalloc (sizeof (struct hash_control)); | |
258 | ||
259 | nd = retval->hash_stat + STATLENGTH; | |
260 | for (ip = retval->hash_stat; ip < nd; ip++) | |
261 | *ip = 0; | |
262 | ||
263 | retval->hash_stat[STAT_SIZE] = 1 << START_POWER; | |
264 | retval->hash_mask = (1 << START_POWER) - 1; | |
265 | retval->hash_sizelog = START_POWER; | |
266 | /* works for 1's compl ok */ | |
267 | retval->hash_where = room; | |
268 | retval->hash_wall = | |
269 | wall = room + (1 << START_POWER); | |
270 | retval->hash_full = (1 << START_POWER) / 2; | |
271 | for (entry = room; entry <= wall; entry++) | |
272 | entry->hash_string = NULL; | |
273 | return retval; | |
fecd2382 RP |
274 | } |
275 | ||
276 | /* | |
277 | * h a s h _ d i e ( ) | |
278 | * | |
279 | * Table should be empty, but this is not checked. | |
280 | * To empty the table, try hash_apply()ing a symbol deleter. | |
281 | * Return to free memory both the hash table and it's control | |
282 | * block. | |
283 | * 'handle' has no meaning after this function. | |
284 | * No errors are recoverable. | |
285 | */ | |
286 | void | |
95ac738e KR |
287 | hash_die (handle) |
288 | struct hash_control *handle; | |
fecd2382 | 289 | { |
95ac738e KR |
290 | free ((char *) handle->hash_where); |
291 | free ((char *) handle); | |
fecd2382 RP |
292 | } |
293 | \f | |
294 | /* | |
295 | * h a s h _ s a y ( ) | |
296 | * | |
297 | * Return the size of the statistics table, and as many statistics as | |
298 | * we can until either (a) we have run out of statistics or (b) caller | |
299 | * has run out of buffer. | |
300 | * NOTE: hash_say treats all statistics alike. | |
301 | * These numbers may change with time, due to insertions, deletions | |
302 | * and expansions of the table. | |
303 | * The first "statistic" returned is the length of hash_stat[]. | |
304 | * Then contents of hash_stat[] are read out (in ascending order) | |
305 | * until your buffer or hash_stat[] is exausted. | |
306 | */ | |
307 | void | |
95ac738e KR |
308 | hash_say (handle, buffer, bufsiz) |
309 | struct hash_control *handle; | |
310 | int buffer[ /*bufsiz*/ ]; | |
311 | int bufsiz; | |
fecd2382 | 312 | { |
95ac738e KR |
313 | int *nd; /* limit of statistics block */ |
314 | int *ip; /* scan statistics */ | |
315 | ||
316 | ip = handle->hash_stat; | |
317 | nd = ip + min (bufsiz - 1, STATLENGTH); | |
318 | if (bufsiz > 0) /* trust nothing! bufsiz<=0 is dangerous */ | |
319 | { | |
320 | *buffer++ = STATLENGTH; | |
321 | for (; ip < nd; ip++, buffer++) | |
322 | { | |
323 | *buffer = *ip; | |
324 | } | |
325 | } | |
fecd2382 RP |
326 | } |
327 | \f | |
328 | /* | |
329 | * h a s h _ d e l e t e ( ) | |
330 | * | |
331 | * Try to delete a symbol from the table. | |
332 | * If it was there, return its value (and adjust STAT_USED). | |
333 | * Otherwise, return NULL. | |
334 | * Anyway, the symbol is not present after this function. | |
335 | * | |
336 | */ | |
95ac738e KR |
337 | PTR /* NULL if string not in table, else */ |
338 | /* returns value of deleted symbol */ | |
339 | hash_delete (handle, string) | |
340 | struct hash_control *handle; | |
341 | const char *string; | |
fecd2382 | 342 | { |
95ac738e KR |
343 | PTR retval; |
344 | struct hash_entry *entry; | |
345 | ||
346 | entry = hash_ask (handle, string, STAT__WRITE); | |
347 | if (hash_found) | |
348 | { | |
349 | retval = entry->hash_value; | |
350 | entry->hash_string = DELETED; | |
351 | handle->hash_stat[STAT_USED] -= 1; | |
fecd2382 | 352 | #ifdef SUSPECT |
95ac738e KR |
353 | if (handle->hash_stat[STAT_USED] < 0) |
354 | { | |
355 | error ("hash_delete"); | |
356 | } | |
a39116f1 | 357 | #endif /* def SUSPECT */ |
95ac738e KR |
358 | } |
359 | else | |
360 | { | |
361 | retval = NULL; | |
362 | } | |
363 | return (retval); | |
fecd2382 RP |
364 | } |
365 | \f | |
366 | /* | |
367 | * h a s h _ r e p l a c e ( ) | |
368 | * | |
369 | * Try to replace the old value of a symbol with a new value. | |
370 | * Normally return the old value. | |
371 | * Return NULL and don't change the table if the symbol is not already | |
372 | * in the table. | |
373 | */ | |
95ac738e KR |
374 | PTR |
375 | hash_replace (handle, string, value) | |
376 | struct hash_control *handle; | |
377 | const char *string; | |
378 | PTR value; | |
fecd2382 | 379 | { |
95ac738e KR |
380 | struct hash_entry *entry; |
381 | char *retval; | |
382 | ||
383 | entry = hash_ask (handle, string, STAT__WRITE); | |
384 | if (hash_found) | |
385 | { | |
386 | retval = entry->hash_value; | |
387 | entry->hash_value = value; | |
388 | } | |
389 | else | |
390 | { | |
391 | retval = NULL; | |
392 | } | |
393 | ; | |
394 | return retval; | |
fecd2382 RP |
395 | } |
396 | \f | |
397 | /* | |
398 | * h a s h _ i n s e r t ( ) | |
399 | * | |
400 | * Insert a (symbol-string, value) into the hash table. | |
95ac738e | 401 | * Return an error string, 0 means OK. |
fecd2382 RP |
402 | * It is an 'error' to insert an existing symbol. |
403 | */ | |
404 | ||
95ac738e KR |
405 | const char * /* return error string */ |
406 | hash_insert (handle, string, value) | |
407 | struct hash_control *handle; | |
408 | const char *string; | |
409 | PTR value; | |
fecd2382 | 410 | { |
95ac738e KR |
411 | struct hash_entry *entry; |
412 | const char *retval; | |
413 | ||
414 | retval = 0; | |
415 | if (handle->hash_stat[STAT_USED] > handle->hash_full) | |
416 | { | |
417 | retval = hash_grow (handle); | |
418 | } | |
419 | if (!retval) | |
420 | { | |
421 | entry = hash_ask (handle, string, STAT__WRITE); | |
422 | if (hash_found) | |
423 | { | |
424 | retval = "exists"; | |
425 | } | |
426 | else | |
427 | { | |
428 | entry->hash_value = value; | |
429 | entry->hash_string = string; | |
430 | handle->hash_stat[STAT_USED] += 1; | |
431 | } | |
432 | } | |
433 | return retval; | |
fecd2382 RP |
434 | } |
435 | \f | |
436 | /* | |
437 | * h a s h _ j a m ( ) | |
438 | * | |
439 | * Regardless of what was in the symbol table before, after hash_jam() | |
440 | * the named symbol has the given value. The symbol is either inserted or | |
441 | * (its value is) relpaced. | |
95ac738e | 442 | * An error message string is returned, 0 means OK. |
fecd2382 RP |
443 | * |
444 | * WARNING: this may decide to grow the hashed symbol table. | |
445 | * To do this, we call hash_grow(), WHICH WILL recursively CALL US. | |
446 | * | |
447 | * We report status internally: hash_found is TRUE if we replaced, but | |
448 | * false if we inserted. | |
449 | */ | |
95ac738e KR |
450 | const char * |
451 | hash_jam (handle, string, value) | |
452 | struct hash_control *handle; | |
453 | const char *string; | |
454 | PTR value; | |
fecd2382 | 455 | { |
95ac738e KR |
456 | const char *retval; |
457 | struct hash_entry *entry; | |
458 | ||
459 | retval = 0; | |
460 | if (handle->hash_stat[STAT_USED] > handle->hash_full) | |
461 | { | |
462 | retval = hash_grow (handle); | |
463 | } | |
464 | if (!retval) | |
465 | { | |
466 | entry = hash_ask (handle, string, STAT__WRITE); | |
467 | if (!hash_found) | |
468 | { | |
469 | entry->hash_string = string; | |
470 | handle->hash_stat[STAT_USED] += 1; | |
471 | } | |
472 | entry->hash_value = value; | |
473 | } | |
474 | return retval; | |
fecd2382 RP |
475 | } |
476 | ||
477 | /* | |
478 | * h a s h _ g r o w ( ) | |
479 | * | |
480 | * Grow a new (bigger) hash table from the old one. | |
481 | * We choose to double the hash table's size. | |
95ac738e | 482 | * Return a human-scrutible error string: 0 if OK. |
fecd2382 RP |
483 | * Warning! This uses hash_jam(), which had better not recurse |
484 | * back here! Hash_jam() conditionally calls us, but we ALWAYS | |
485 | * call hash_jam()! | |
486 | * Internal. | |
487 | */ | |
95ac738e KR |
488 | static const char * |
489 | hash_grow (handle) /* make a hash table grow */ | |
490 | struct hash_control *handle; | |
fecd2382 | 491 | { |
95ac738e KR |
492 | struct hash_entry *newwall; |
493 | struct hash_entry *newwhere; | |
494 | struct hash_entry *newtrack; | |
495 | struct hash_entry *oldtrack; | |
496 | struct hash_entry *oldwhere; | |
497 | struct hash_entry *oldwall; | |
498 | int temp; | |
499 | int newsize; | |
500 | const char *string; | |
501 | const char *retval; | |
fecd2382 | 502 | #ifdef SUSPECT |
95ac738e | 503 | int oldused; |
fecd2382 | 504 | #endif |
95ac738e KR |
505 | |
506 | /* | |
507 | * capture info about old hash table | |
508 | */ | |
509 | oldwhere = handle->hash_where; | |
510 | oldwall = handle->hash_wall; | |
fecd2382 | 511 | #ifdef SUSPECT |
95ac738e | 512 | oldused = handle->hash_stat[STAT_USED]; |
fecd2382 | 513 | #endif |
95ac738e KR |
514 | /* |
515 | * attempt to get enough room for a hash table twice as big | |
516 | */ | |
517 | temp = handle->hash_stat[STAT_SIZE]; | |
518 | if ((newwhere = ((struct hash_entry *) | |
519 | xmalloc ((unsigned long) ((temp + temp + 1) | |
520 | * sizeof (struct hash_entry))))) | |
521 | != NULL) | |
522 | /* +1 for wall slot */ | |
523 | { | |
524 | retval = 0; /* assume success until proven otherwise */ | |
525 | /* | |
526 | * have enough room: now we do all the work. | |
527 | * double the size of everything in handle, | |
528 | * note: hash_mask frob works for 1's & for 2's complement machines | |
529 | */ | |
530 | handle->hash_mask = handle->hash_mask + handle->hash_mask + 1; | |
531 | handle->hash_stat[STAT_SIZE] <<= 1; | |
532 | newsize = handle->hash_stat[STAT_SIZE]; | |
533 | handle->hash_where = newwhere; | |
534 | handle->hash_full <<= 1; | |
535 | handle->hash_sizelog += 1; | |
536 | handle->hash_stat[STAT_USED] = 0; | |
537 | handle->hash_wall = | |
538 | newwall = newwhere + newsize; | |
539 | /* | |
540 | * set all those pesky new slots to vacant. | |
541 | */ | |
542 | for (newtrack = newwhere; newtrack <= newwall; newtrack++) | |
543 | { | |
544 | newtrack->hash_string = NULL; | |
545 | } | |
546 | /* | |
547 | * we will do a scan of the old table, the hard way, using the | |
548 | * new control block to re-insert the data into new hash table. | |
549 | */ | |
550 | handle->hash_stat[STAT_USED] = 0; /* inserts will bump it up to correct */ | |
551 | for (oldtrack = oldwhere; oldtrack < oldwall; oldtrack++) | |
552 | if (((string = oldtrack->hash_string) != NULL) && string != DELETED) | |
553 | if ((retval = hash_jam (handle, string, oldtrack->hash_value))) | |
554 | break; | |
555 | ||
fecd2382 | 556 | #ifdef SUSPECT |
95ac738e KR |
557 | if (!retval && handle->hash_stat[STAT_USED] != oldused) |
558 | { | |
559 | retval = "hash_used"; | |
560 | } | |
fecd2382 | 561 | #endif |
95ac738e KR |
562 | if (!retval) |
563 | { | |
564 | /* | |
565 | * we have a completely faked up control block. | |
566 | * return the old hash table. | |
567 | */ | |
568 | free ((char *) oldwhere); | |
569 | /* | |
570 | * Here with success. retval is already 0. | |
571 | */ | |
572 | } | |
573 | } | |
574 | else | |
575 | { | |
576 | retval = "no room"; | |
577 | } | |
578 | return retval; | |
fecd2382 RP |
579 | } |
580 | \f | |
581 | /* | |
582 | * h a s h _ a p p l y ( ) | |
583 | * | |
584 | * Use this to scan each entry in symbol table. | |
585 | * For each symbol, this calls (applys) a nominated function supplying the | |
586 | * symbol's value (and the symbol's name). | |
587 | * The idea is you use this to destroy whatever is associted with | |
588 | * any values in the table BEFORE you destroy the table with hash_die. | |
589 | * Of course, you can use it for other jobs; whenever you need to | |
590 | * visit all extant symbols in the table. | |
591 | * | |
592 | * We choose to have a call-you-back idea for two reasons: | |
593 | * asthetic: it is a neater idea to use apply than an explicit loop | |
594 | * sensible: if we ever had to grow the symbol table (due to insertions) | |
595 | * then we would lose our place in the table when we re-hashed | |
596 | * symbols into the new table in a different order. | |
597 | * | |
598 | * The order symbols are visited depends entirely on the hashing function. | |
599 | * Whenever you insert a (symbol, value) you risk expanding the table. If | |
600 | * you do expand the table, then the hashing function WILL change, so you | |
601 | * MIGHT get a different order of symbols visited. In other words, if you | |
602 | * want the same order of visiting symbols as the last time you used | |
603 | * hash_apply() then you better not have done any hash_insert()s or | |
604 | * hash_jam()s since the last time you used hash_apply(). | |
605 | * | |
606 | * In future we may use the value returned by your nominated function. | |
607 | * One idea is to abort the scan if, after applying the function to a | |
608 | * certain node, the function returns a certain code. | |
609 | * To be safe, please make your functions of type char *. If you always | |
610 | * return NULL, then the scan will complete, visiting every symbol in | |
611 | * the table exactly once. ALL OTHER RETURNED VALUES have no meaning yet! | |
612 | * Caveat Actor! | |
613 | * | |
614 | * The function you supply should be of the form: | |
615 | * char * myfunct(string,value) | |
616 | * char * string; |* the symbol's name *| | |
617 | * char * value; |* the symbol's value *| | |
618 | * { | |
619 | * |* ... *| | |
620 | * return(NULL); | |
621 | * } | |
622 | * | |
623 | * The returned value of hash_apply() is (char*)NULL. In future it may return | |
624 | * other values. NULL means "completed scan OK". Other values have no meaning | |
625 | * yet. (The function has no graceful failures.) | |
626 | */ | |
627 | char * | |
95ac738e KR |
628 | hash_apply (handle, function) |
629 | struct hash_control *handle; | |
630 | char *(*function) (); | |
fecd2382 | 631 | { |
95ac738e KR |
632 | struct hash_entry *entry; |
633 | struct hash_entry *wall; | |
634 | ||
635 | wall = handle->hash_wall; | |
636 | for (entry = handle->hash_where; entry < wall; entry++) | |
637 | { | |
638 | if (islive (entry)) /* silly code: tests entry->string twice! */ | |
639 | { | |
640 | (*function) (entry->hash_string, entry->hash_value); | |
641 | } | |
642 | } | |
643 | return (NULL); | |
fecd2382 RP |
644 | } |
645 | \f | |
646 | /* | |
647 | * h a s h _ f i n d ( ) | |
648 | * | |
649 | * Given symbol string, find value (if any). | |
650 | * Return found value or NULL. | |
651 | */ | |
95ac738e KR |
652 | PTR |
653 | hash_find (handle, string) | |
654 | struct hash_control *handle; | |
655 | const char *string; | |
fecd2382 | 656 | { |
95ac738e KR |
657 | struct hash_entry *entry; |
658 | ||
659 | entry = hash_ask (handle, string, STAT__READ); | |
660 | if (hash_found) | |
661 | return entry->hash_value; | |
662 | else | |
663 | return NULL; | |
fecd2382 RP |
664 | } |
665 | \f | |
666 | /* | |
667 | * h a s h _ a s k ( ) | |
668 | * | |
669 | * Searches for given symbol string. | |
670 | * Return the slot where it OUGHT to live. It may be there. | |
671 | * Return hash_found: TRUE only if symbol is in that slot. | |
672 | * Access argument is to help keep statistics in control block. | |
673 | * Internal. | |
674 | */ | |
675 | static struct hash_entry * /* string slot, may be empty or deleted */ | |
95ac738e KR |
676 | hash_ask (handle, string, access) |
677 | struct hash_control *handle; | |
678 | const char *string; | |
679 | int access; /* access type */ | |
fecd2382 | 680 | { |
95ac738e | 681 | const char *s; |
95ac738e KR |
682 | struct hash_entry *slot; |
683 | int collision; /* count collisions */ | |
684 | ||
685 | /* start looking here */ | |
686 | slot = handle->hash_where + hash_code (handle, string); | |
687 | ||
688 | handle->hash_stat[STAT_ACCESS + access] += 1; | |
689 | collision = 0; | |
690 | hash_found = FALSE; | |
691 | while (((s = slot->hash_string) != NULL) && s != DELETED) | |
692 | { | |
95ac738e KR |
693 | if (string == s || !strcmp (string, s)) |
694 | hash_found = TRUE; | |
95ac738e KR |
695 | if (hash_found) |
696 | break; | |
697 | collision++; | |
698 | slot++; | |
699 | } | |
700 | /* | |
701 | * slot: return: | |
702 | * in use: we found string slot | |
703 | * at empty: | |
704 | * at wall: we fell off: wrap round ???? | |
705 | * in table: dig here slot | |
706 | * at DELETED: dig here slot | |
707 | */ | |
708 | if (slot == handle->hash_wall) | |
709 | { | |
710 | slot = handle->hash_where;/* now look again */ | |
711 | while (((s = slot->hash_string) != NULL) && s != DELETED) | |
712 | { | |
95ac738e KR |
713 | if (string == s || !strcmp (string, s)) |
714 | hash_found = TRUE; | |
95ac738e KR |
715 | collision++; |
716 | slot++; | |
717 | } | |
718 | /* | |
719 | * slot: return: | |
720 | * in use: we found it slot | |
721 | * empty: wall: ERROR IMPOSSIBLE !!!! | |
722 | * in table: dig here slot | |
723 | * DELETED:dig here slot | |
724 | */ | |
725 | } | |
726 | handle->hash_stat[STAT_COLLIDE + access] += collision; | |
727 | return (slot); /* also return hash_found */ | |
fecd2382 RP |
728 | } |
729 | \f | |
730 | /* | |
731 | * h a s h _ c o d e | |
732 | * | |
733 | * Does hashing of symbol string to hash number. | |
734 | * Internal. | |
735 | */ | |
736 | static int | |
95ac738e KR |
737 | hash_code (handle, string) |
738 | struct hash_control *handle; | |
739 | const char *string; | |
fecd2382 | 740 | { |
b2683e09 KR |
741 | #if 1 /* There seems to be some interesting property of this function |
742 | that prevents the bfd version below from being an adequate | |
743 | substitute. @@ Figure out what this property is! */ | |
95ac738e KR |
744 | long h; /* hash code built here */ |
745 | long c; /* each character lands here */ | |
746 | int n; /* Amount to shift h by */ | |
747 | ||
748 | n = (handle->hash_sizelog - 3); | |
749 | h = 0; | |
750 | while ((c = *string++) != 0) | |
751 | { | |
752 | h += c; | |
753 | h = (h << 3) + (h >> n) + c; | |
754 | } | |
755 | return (h & handle->hash_mask); | |
756 | #else | |
b2683e09 | 757 | /* from bfd */ |
95ac738e KR |
758 | unsigned long h = 0; |
759 | unsigned int len = 0; | |
760 | unsigned int c; | |
761 | ||
762 | while ((c = *string++) != 0) | |
763 | { | |
764 | h += c + (c << 17); | |
765 | h ^= h >> 2; | |
766 | ++len; | |
767 | } | |
768 | h += len + (len << 17); | |
769 | h ^= h >> 2; | |
770 | return h & handle->hash_mask; | |
771 | #endif | |
fecd2382 RP |
772 | } |
773 | \f | |
774 | /* | |
775 | * Here is a test program to exercise above. | |
776 | */ | |
777 | #ifdef TEST | |
778 | ||
779 | #define TABLES (6) /* number of hash tables to maintain */ | |
a39116f1 | 780 | /* (at once) in any testing */ |
fecd2382 RP |
781 | #define STATBUFSIZE (12) /* we can have 12 statistics */ |
782 | ||
783 | int statbuf[STATBUFSIZE]; /* display statistics here */ | |
784 | char answer[100]; /* human farts here */ | |
95ac738e KR |
785 | char *hashtable[TABLES]; /* we test many hash tables at once */ |
786 | char *h; /* points to curent hash_control */ | |
787 | char **pp; | |
788 | char *p; | |
789 | char *name; | |
790 | char *value; | |
791 | int size; | |
792 | int used; | |
793 | char command; | |
794 | int number; /* number 0:TABLES-1 of current hashed */ | |
a39116f1 | 795 | /* symbol table */ |
fecd2382 | 796 | |
95ac738e | 797 | main () |
fecd2382 | 798 | { |
95ac738e KR |
799 | char (*applicatee ()); |
800 | char *destroy (); | |
801 | char *what (); | |
802 | int *ip; | |
803 | ||
804 | number = 0; | |
805 | h = 0; | |
806 | printf ("type h <RETURN> for help\n"); | |
807 | for (;;) | |
808 | { | |
809 | printf ("hash_test command: "); | |
810 | gets (answer); | |
811 | command = answer[0]; | |
812 | if (isupper (command)) | |
813 | command = tolower (command); /* ecch! */ | |
814 | switch (command) | |
815 | { | |
816 | case '#': | |
817 | printf ("old hash table #=%d.\n", number); | |
818 | whattable (); | |
819 | break; | |
820 | case '?': | |
821 | for (pp = hashtable; pp < hashtable + TABLES; pp++) | |
822 | { | |
823 | printf ("address of hash table #%d control block is %xx\n" | |
824 | ,pp - hashtable, *pp); | |
825 | } | |
826 | break; | |
827 | case 'a': | |
828 | hash_apply (h, applicatee); | |
829 | break; | |
830 | case 'd': | |
831 | hash_apply (h, destroy); | |
832 | hash_die (h); | |
833 | break; | |
834 | case 'f': | |
835 | p = hash_find (h, name = what ("symbol")); | |
836 | printf ("value of \"%s\" is \"%s\"\n", name, p ? p : "NOT-PRESENT"); | |
837 | break; | |
838 | case 'h': | |
839 | printf ("# show old, select new default hash table number\n"); | |
840 | printf ("? display all hashtable control block addresses\n"); | |
841 | printf ("a apply a simple display-er to each symbol in table\n"); | |
842 | printf ("d die: destroy hashtable\n"); | |
843 | printf ("f find value of nominated symbol\n"); | |
844 | printf ("h this help\n"); | |
845 | printf ("i insert value into symbol\n"); | |
846 | printf ("j jam value into symbol\n"); | |
847 | printf ("n new hashtable\n"); | |
848 | printf ("r replace a value with another\n"); | |
849 | printf ("s say what %% of table is used\n"); | |
850 | printf ("q exit this program\n"); | |
851 | printf ("x delete a symbol from table, report its value\n"); | |
852 | break; | |
853 | case 'i': | |
854 | p = hash_insert (h, name = what ("symbol"), value = what ("value")); | |
855 | if (p) | |
856 | { | |
857 | printf ("symbol=\"%s\" value=\"%s\" error=%s\n", name, value, | |
858 | p); | |
859 | } | |
860 | break; | |
861 | case 'j': | |
862 | p = hash_jam (h, name = what ("symbol"), value = what ("value")); | |
863 | if (p) | |
fecd2382 | 864 | { |
95ac738e | 865 | printf ("symbol=\"%s\" value=\"%s\" error=%s\n", name, value, p); |
fecd2382 | 866 | } |
95ac738e KR |
867 | break; |
868 | case 'n': | |
869 | h = hashtable[number] = (char *) hash_new (); | |
870 | break; | |
871 | case 'q': | |
872 | exit (EXIT_SUCCESS); | |
873 | case 'r': | |
874 | p = hash_replace (h, name = what ("symbol"), value = what ("value")); | |
875 | printf ("old value was \"%s\"\n", p ? p : "{}"); | |
876 | break; | |
877 | case 's': | |
878 | hash_say (h, statbuf, STATBUFSIZE); | |
879 | for (ip = statbuf; ip < statbuf + STATBUFSIZE; ip++) | |
880 | { | |
881 | printf ("%d ", *ip); | |
882 | } | |
883 | printf ("\n"); | |
884 | break; | |
885 | case 'x': | |
886 | p = hash_delete (h, name = what ("symbol")); | |
887 | printf ("old value was \"%s\"\n", p ? p : "{}"); | |
888 | break; | |
889 | default: | |
890 | printf ("I can't understand command \"%c\"\n", command); | |
891 | break; | |
892 | } | |
893 | } | |
fecd2382 RP |
894 | } |
895 | ||
896 | char * | |
95ac738e KR |
897 | what (description) |
898 | char *description; | |
fecd2382 | 899 | { |
95ac738e KR |
900 | char *retval; |
901 | char *malloc (); | |
902 | ||
903 | printf (" %s : ", description); | |
904 | gets (answer); | |
905 | /* will one day clean up answer here */ | |
906 | retval = malloc (strlen (answer) + 1); | |
907 | if (!retval) | |
908 | { | |
909 | error ("room"); | |
910 | } | |
911 | (void) strcpy (retval, answer); | |
912 | return (retval); | |
fecd2382 RP |
913 | } |
914 | ||
915 | char * | |
95ac738e KR |
916 | destroy (string, value) |
917 | char *string; | |
918 | char *value; | |
fecd2382 | 919 | { |
95ac738e KR |
920 | free (string); |
921 | free (value); | |
922 | return (NULL); | |
fecd2382 RP |
923 | } |
924 | ||
925 | ||
926 | char * | |
95ac738e KR |
927 | applicatee (string, value) |
928 | char *string; | |
929 | char *value; | |
fecd2382 | 930 | { |
95ac738e KR |
931 | printf ("%.20s-%.20s\n", string, value); |
932 | return (NULL); | |
fecd2382 RP |
933 | } |
934 | ||
95ac738e KR |
935 | whattable () /* determine number: what hash table to use */ |
936 | /* also determine h: points to hash_control */ | |
fecd2382 | 937 | { |
95ac738e KR |
938 | |
939 | for (;;) | |
940 | { | |
941 | printf (" what hash table (%d:%d) ? ", 0, TABLES - 1); | |
942 | gets (answer); | |
943 | sscanf (answer, "%d", &number); | |
944 | if (number >= 0 && number < TABLES) | |
945 | { | |
946 | h = hashtable[number]; | |
947 | if (!h) | |
fecd2382 | 948 | { |
95ac738e | 949 | printf ("warning: current hash-table-#%d. has no hash-control\n", number); |
fecd2382 | 950 | } |
95ac738e KR |
951 | return; |
952 | } | |
953 | else | |
954 | { | |
955 | printf ("invalid hash table number: %d\n", number); | |
956 | } | |
957 | } | |
fecd2382 RP |
958 | } |
959 | ||
960 | ||
961 | ||
962 | #endif /* #ifdef TEST */ | |
963 | ||
8b228fe9 | 964 | /* end of hash.c */ |