home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 1 / 1969 < prev    next >
Encoding:
Text File  |  1990-12-28  |  10.0 KB  |  424 lines

  1. Newsgroups: alt.sources
  2. From: chris@mimsy.umd.edu (Chris Torek)
  3. Subject: [comp.lang.c] Re: hash function for text in C
  4. Message-ID: <1990Oct18.184451.18734@math.lsa.umich.edu>
  5. Date: Thu, 18 Oct 90 18:44:51 GMT
  6.  
  7. Archive-name: hash/18-Oct-90
  8. Original-posting-by: chris@mimsy.umd.edu (Chris Torek)
  9. Original-subject: Re: hash function for text in C
  10. Reposted-by: emv@math.lsa.umich.edu (Edward Vielmetti)
  11.  
  12. [Reposted from comp.lang.c.
  13. Comments on this service to emv@math.lsa.umich.edu (Edward Vielmetti).]
  14.  
  15. The following implements expanding chained hash tables for strings and
  16. numbers.  This is unmodified from a special-purpose program (having to
  17. do with reading a large number of files with name=id pairs and doing
  18. various operations on them).  Chain lengths are not monitored; instead,
  19. the table is invariably expanded whenever it becomes 2/3 full.  Entries
  20. may be neither removed nor modified.
  21.  
  22. An essentially-unrelated function called `string' maintains a string
  23. pool such that string(x) == string(y) iff strcmp(x,y)==0 (the program
  24. typically stores each name several times, and often needs to test for
  25. name equality, so this helps there).
  26.  
  27. : Run this shell script with "sh" not "csh"
  28. PATH=/bin:/usr/bin:/usr/ucb:/etc:$PATH
  29. export PATH
  30. all=false
  31. if [ x$1 = x-a ]; then
  32.     all=true
  33. fi
  34. echo Extracting hash.h
  35. sed 's/^X//' <<'//go.sysin dd *' >hash.h
  36. X/*
  37. X * $Id: hash.h,v 1.1 90/09/24 23:58:38 chris Exp $
  38. X *
  39. X * Hash table entries keep track of name (or id) = value pairs.
  40. X * Values are simply pointers.  Hash tables themselves are named
  41. X * (for debugging).
  42. X */
  43. X
  44. Xstruct    hashtab;
  45. X
  46. X/*
  47. X * The `ins' functions return nonzero if the old value existed,
  48. X * without changing the value.
  49. X * The iterate functions calls a given function with name,value
  50. X * or id,value pairs.
  51. X */
  52. Xstruct    hashtab *ht_new();    /* given name, create new hash table */
  53. Xchar    *ht_nget();        /* given table and name, get value */
  54. Xchar    *ht_iget();        /* given table and ID, get value */
  55. Xint    ht_nins();        /* given table and name, insert new value */
  56. Xint    ht_iins();        /* given table and id, insert new value */
  57. Xvoid    ht_niterate();        /* given table and function, iterate */
  58. Xvoid    ht_iiterate();        /* given table and function, iterate */
  59. X
  60. X/*
  61. X * Some things that ought not to be here, but are anyway.
  62. X * goodnumber() takes a number of objects and a size and returns
  63. X * a new number of objects, such that malloc(goodnumber(n,size)*size)
  64. X * calls malloc with a `good' size value (resulting in less wasted
  65. X * memory).  emalloc is malloc with program-abort on out-of-memory.
  66. X * string() makes a `read-only' copy of a string, reusing the previous
  67. X * copy if any.
  68. X */
  69. Xint    goodnumber();        /* given n & sizeof, return new n */
  70. Xchar    *emalloc();        /* malloc, exit on error */
  71. Xchar    *string();        /* make an `ideal' copy of a string */
  72. //go.sysin dd *
  73. if [ `wc -c < hash.h` != 1415 ]; then
  74.     made=false
  75.     echo error transmitting hash.h --
  76.     echo length should be 1415, not `wc -c < hash.h`
  77. else
  78.     made=true
  79. fi
  80. if $all; then
  81.     echo '    Changing owner to bin'
  82.     chown bin hash.h
  83. else
  84.     echo '    Original owner was bin'
  85. fi
  86. if $made; then
  87.     chmod 444 hash.h
  88.     echo -n '    '; ls -ld hash.h
  89. fi
  90. echo Extracting hash.c
  91. sed 's/^X//' <<'//go.sysin dd *' >hash.c
  92. X#ifndef lint
  93. Xstatic char rcsid[] = "$Id: hash.c,v 1.2 90/10/02 13:32:23 chris Exp $";
  94. X#endif
  95. X
  96. X/*
  97. X * Hash table routines.
  98. X */
  99. X
  100. X#include <stdio.h>
  101. X#include <stdlib.h>
  102. X#include <string.h>
  103. X#include "hash.h"
  104. X
  105. X/*
  106. X * Hash table entries keep track of name=value pairs.
  107. X * The names may be numeric IDs instead (by having a null name).
  108. X */
  109. Xstruct hashent {
  110. X    struct    hashent *h_next;/* next in chain */
  111. X    int    h_hash;        /* hash value or ID */
  112. X    char    *h_name;    /* name (null if from numeric ID) */
  113. X    char    *h_value;    /* value */
  114. X};
  115. X
  116. Xstruct hashtab {
  117. X    int    ht_size;    /* size (power of 2) */
  118. X    int    ht_mask;    /* == ht_size - 1 */
  119. X    int    ht_used;    /* number of entries used */
  120. X    int    ht_lim;        /* when to expand */
  121. X    struct    hashent **ht_tab;/* base of table */
  122. X    char    ht_name[1];    /* table name; actually larger */
  123. X};
  124. X
  125. Xextern char *progname;
  126. X
  127. Xchar *
  128. Xemalloc(n)
  129. X    size_t n;
  130. X{
  131. X    register char *p = malloc(n);
  132. X
  133. X    if (p == NULL) {
  134. X        (void) fprintf(stderr, "%s: out of memory\n", progname);
  135. X        exit(1);
  136. X    }
  137. X    return (p);
  138. X}
  139. X
  140. X/* round up to next multiple of y, where y is a power of 2 */
  141. X#define    ROUND(x, y) (((x) + (y) - 1) & ~((y) - 1))
  142. X
  143. X/* compute a `good' number of objects to allocate via malloc */
  144. Xint
  145. Xgoodnumber(n, s)
  146. X    int n;
  147. X    size_t s;
  148. X{
  149. X
  150. X    /* 16384 is a guess at a good page size for malloc */
  151. X    /* 32 is a guess at malloc's overhead */
  152. X    return ((int)((ROUND(n * s + 32, 16384) - 32) / s));
  153. X}
  154. X
  155. X/*
  156. X * Make a new hash table.
  157. X */
  158. Xstruct hashtab *
  159. Xht_new(name)
  160. X    char *name;
  161. X{
  162. X    register struct hashtab *ht;
  163. X    register struct hashent **h;
  164. X    register int n;
  165. X
  166. X    ht = (struct hashtab *)emalloc(sizeof *ht + strlen(name));
  167. X    ht->ht_tab = h = (struct hashent **)emalloc(128 * sizeof *h);
  168. X    ht->ht_size = 128;
  169. X    ht->ht_mask = 127;
  170. X    for (n = 128; --n >= 0;)
  171. X        *h++ = NULL;
  172. X    ht->ht_used = 0;
  173. X    ht->ht_lim = (128 * 2) / 3;
  174. X    (void) strcpy(ht->ht_name, name);
  175. X    return (ht);
  176. X}
  177. X
  178. X/*
  179. X * Expand an existing hash table.
  180. X */
  181. Xstatic void
  182. Xht_expand(ht)
  183. X    register struct hashtab *ht;
  184. X{
  185. X    register int n = ht->ht_size * 2, i;
  186. X    register struct hashent *p, **h, **oldh, *q;
  187. X
  188. X    h = (struct hashent **)emalloc(n * sizeof *h);
  189. X    for (i = n; --i >= 0;)
  190. X        *h++ = NULL;
  191. X    h -= n;
  192. X    oldh = ht->ht_tab;
  193. X    n--;
  194. X    for (i = ht->ht_size; --i >= 0;) {
  195. X        for (p = *oldh++; p != NULL; p = q) {
  196. X            q = p->h_next;
  197. X            p->h_next = h[p->h_hash & n];
  198. X            h[p->h_hash & n] = p;
  199. X        }
  200. X    }
  201. X    free((char *)ht->ht_tab);
  202. X    ht->ht_tab = h;
  203. X    ht->ht_mask = n;
  204. X    ht->ht_size = ++n;
  205. X    ht->ht_lim = (n * 2) / 3;
  206. X}
  207. X    
  208. X/*
  209. X * Make a new hash entry.  Its h_next will be NULL.
  210. X */
  211. Xstatic struct hashent *
  212. Xnewhashent(hash, name, value)
  213. X    int hash;
  214. X    char *name, *value;
  215. X{
  216. X    static struct hashent *hfree;
  217. X    register struct hashent *h;
  218. X    register int n, nalloc;
  219. X
  220. X    if ((h = hfree) != NULL)
  221. X        hfree = h->h_next;
  222. X    else {
  223. X        nalloc = goodnumber(2, sizeof *h);    /* need at least 2 */
  224. X        hfree = h = (struct hashent *)emalloc(nalloc * sizeof *h) + 1;
  225. X        for (n = nalloc - 2; --n >= 0; h++)
  226. X            h->h_next = h + 1;
  227. X        h->h_next = NULL;
  228. X        h -= nalloc - 1;
  229. X    }
  230. X    h->h_next = NULL;
  231. X    h->h_hash = hash;
  232. X    h->h_name = name;
  233. X    h->h_value = value;
  234. X    return (h);
  235. X}
  236. X
  237. X#define    HASH(str, h, p) \
  238. X    for (p = str, h = 0; *p;) h = (h << 5) - h + *p++
  239. X
  240. X/*
  241. X * Look up a name=value.
  242. X */
  243. Xchar *
  244. Xht_nget(ht, name)
  245. X    register struct hashtab *ht;
  246. X    char *name;
  247. X{
  248. X    register char *p;
  249. X    register int hash;
  250. X    register struct hashent *h;
  251. X
  252. X    HASH(name, hash, p);
  253. X    p = name;
  254. X    for (h = ht->ht_tab[hash & ht->ht_mask]; h != NULL; h = h->h_next)
  255. X        if (h->h_hash == hash && h->h_name != NULL &&
  256. X            strcmp(h->h_name, p) == 0)
  257. X            return (h->h_value);
  258. X    return (NULL);
  259. X}
  260. X
  261. X/*
  262. X * Look up an ID=value.
  263. X */
  264. Xchar *
  265. Xht_iget(ht, id)
  266. X    register struct hashtab *ht;
  267. X    register int id;
  268. X{
  269. X    register struct hashent *h;
  270. X
  271. X    for (h = ht->ht_tab[id & ht->ht_mask]; h != NULL; h = h->h_next)
  272. X        if (h->h_hash == id && h->h_name == NULL)
  273. X            return (h->h_value);
  274. X    return (NULL);
  275. X}
  276. X
  277. X/*
  278. X * Insert (do not clobber) a name=value.
  279. X * Return zero on success.
  280. X */
  281. Xint
  282. Xht_nins(ht, name, value)
  283. X    register struct hashtab *ht;
  284. X    char *name, *value;
  285. X{
  286. X    register char *p;
  287. X    register int hash;
  288. X    register struct hashent *h, **hp;
  289. X
  290. X    HASH(name, hash, p);
  291. X    p = name;
  292. X    for (hp = &ht->ht_tab[hash & ht->ht_mask]; (h = *hp) != NULL;
  293. X         hp = &h->h_next)
  294. X        if (h->h_hash == hash && h->h_name != NULL &&
  295. X            strcmp(h->h_name, p) == 0)
  296. X            return (-1);
  297. X    *hp = newhashent(hash, name, value);
  298. X    if (++ht->ht_used > ht->ht_lim)
  299. X        ht_expand(ht);
  300. X    return (0);
  301. X}
  302. X
  303. X/*
  304. X * Insert (do not clobber) an ID=value.
  305. X * Return zero on success.
  306. X */
  307. Xint
  308. Xht_iins(ht, id, value)
  309. X    register struct hashtab *ht;
  310. X    register int id;
  311. X    char *value;
  312. X{
  313. X    register struct hashent *h, **hp;
  314. X
  315. X    for (hp = &ht->ht_tab[id & ht->ht_mask]; (h = *hp) != NULL;
  316. X         hp = &h->h_next)
  317. X        if (h->h_hash == id && h->h_name == NULL)
  318. X            return (-1);
  319. X    *hp = newhashent(id, (char *)NULL, value);
  320. X    if (++ht->ht_used > ht->ht_lim)
  321. X        ht_expand(ht);
  322. X    return (0);
  323. X}
  324. X
  325. X/*
  326. X * Stash a copy of a string away; it will never be freed.
  327. X */
  328. Xstatic char *
  329. Xpoolstr(s)
  330. X    char *s;
  331. X{
  332. X    register char *p;
  333. X    register size_t l = strlen(s) + 1;
  334. X    static char *poolp;
  335. X    static size_t nleft;
  336. X
  337. X    if (nleft < l)
  338. X        poolp = emalloc(nleft = goodnumber(l, 1));
  339. X    bcopy(s, p = poolp, l);
  340. X    poolp += l;
  341. X    return (p);
  342. X}
  343. X
  344. X/*
  345. X * Generate a single unique copy of the given string.
  346. X */
  347. Xchar *
  348. Xstring(s)
  349. X    char *s;
  350. X{
  351. X    register char *p;
  352. X    register int hash;
  353. X    register struct hashent *h, **hp;
  354. X    static struct hashtab *ht;
  355. X
  356. X    if (ht == NULL)
  357. X        ht = ht_new("strings");
  358. X    HASH(s, hash, p);
  359. X    p = s;
  360. X    for (hp = &ht->ht_tab[hash & ht->ht_mask]; (h = *hp) != NULL;
  361. X         hp = &h->h_next)
  362. X        if (h->h_hash == hash && strcmp(h->h_name, p) == 0)
  363. X            return (h->h_name);
  364. X    *hp = h = newhashent(hash, poolstr(s), (char *)NULL);
  365. X    if (++ht->ht_used > ht->ht_lim)
  366. X        ht_expand(ht);
  367. X    return (h->h_name);
  368. X}
  369. X
  370. X/*
  371. X * Call fn on all the name=value pairs.
  372. X */
  373. Xvoid
  374. Xht_niterate(ht, fn)
  375. X    struct hashtab *ht;
  376. X    register void (*fn)();
  377. X{
  378. X    register struct hashent *h, **hp;
  379. X    register int n;
  380. X
  381. X    for (n = ht->ht_size, hp = ht->ht_tab; --n >= 0;)
  382. X        for (h = *hp++; h != NULL; h = h->h_next)
  383. X            if (h->h_name != NULL)
  384. X                (*fn)(h->h_name, h->h_value);
  385. X}
  386. X
  387. X/*
  388. X * Call fn on all the id=value pairs.
  389. X */
  390. Xvoid
  391. Xht_iiterate(ht, fn)
  392. X    struct hashtab *ht;
  393. X    register void (*fn)();
  394. X{
  395. X    register struct hashent *h, **hp;
  396. X    register int n;
  397. X
  398. X    for (n = ht->ht_size, hp = ht->ht_tab; --n >= 0;)
  399. X        for (h = *hp++; h != NULL; h = h->h_next)
  400. X            if (h->h_name == NULL)
  401. X                (*fn)(h->h_hash, h->h_value);
  402. X}
  403. //go.sysin dd *
  404. if [ `wc -c < hash.c` != 6291 ]; then
  405.     made=false
  406.     echo error transmitting hash.c --
  407.     echo length should be 6291, not `wc -c < hash.c`
  408. else
  409.     made=true
  410. fi
  411. if $all; then
  412.     echo '    Changing owner to bin'
  413.     chown bin hash.c
  414. else
  415.     echo '    Original owner was bin'
  416. fi
  417. if $made; then
  418.     chmod 444 hash.c
  419.     echo -n '    '; ls -ld hash.c
  420. fi
  421. -- 
  422. In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 405 2750)
  423. Domain:    chris@cs.umd.edu    Path:    uunet!mimsy!chris
  424.