hash.c 30 KB

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