home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / misc / volume35 / dis / part01 < prev    next >
Encoding:
Text File  |  1993-02-03  |  53.7 KB  |  1,927 lines

  1. Newsgroups: comp.sources.misc
  2. From: bediger@nugget.rmnug.org (Bruce Allen Ediger)
  3. Subject: v35i015:  dis - SPARC/SunOS disassembler, Part01/03
  4. Message-ID: <csm-v35i015=dis.004124@sparky.IMD.Sterling.COM>
  5. X-Md4-Signature: 196bf31dbe988aa6a74f5966bf4855b3
  6. Date: Tue, 2 Feb 1993 06:42:33 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: bediger@nugget.rmnug.org (Bruce Allen Ediger)
  10. Posting-number: Volume 35, Issue 15
  11. Archive-name: dis/part01
  12. Environment: SunOS4.1.x
  13.  
  14. "dis" is a SPARC opcode disassembler.  It should work on most SunOS 4.1 and
  15. up executables and relocatable object files (.o).  I worked from "The SPARC
  16. Architecture Reference Manual", version 8, to define the opcodes.
  17.  
  18. The entry point to the actual disassembly is in decode.c, "decode_instr()".
  19. decode.c, arithmetic.c, destination.c, memory.c contain all of the real
  20. disassembly code.  The other stuff is a driver routine and fluff to do symbol
  21. table decoding, and debugging info inclusion.
  22.  
  23. Header files arithmetic.h, branches.h, formats.h, memory.h are included by 
  24. the actual disassembly code files.
  25.  
  26. It should be relatively easy to wrap the functions in the 4 .c files listed
  27. above with other drivers to implement other object file formats.  Compile 
  28. with NOSYNTHETIC defined to reduce/eliminate any "synthetic" opcodes in 
  29. disassembly.
  30.  
  31. Symbol table and relocation info lookup is done with hash table routines I 
  32. got from CAP 2.0, the Columbia Appletalk Package.  This part of the program 
  33. is fairly dependant on the BSD "nlist" format of relocation info, and "stabs"
  34. format of symbol table.  This part of the code does not lint very cleanly.
  35.  
  36. It's only really been used on Suns, SPARC-clones and NeXT 680x0 boxes.  I 
  37. have no idea if it's really portable.  After contemplation, I don't believe 
  38. it will work on "little-endian" machines, and I have no idea how hard it 
  39. would be to get it to work.  There are an awful lot of assumptions about 
  40. bit patterns and byte ordering implicit in the structs used to represent 
  41. the 32-bit instructions.
  42.  
  43. Bruce
  44. ------------------
  45. #! /bin/sh
  46. # This is a shell archive.  Remove anything before this line, then feed it
  47. # into a shell via "sh file" or similar.  To overwrite existing files,
  48. # type "sh file -c".
  49. # Contents:  README dis.c hash.3 hash.c
  50. # Wrapped by kent@sparky on Tue Feb  2 00:31:40 1993
  51. PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/lbin ; export PATH
  52. echo If this archive is complete, you will see the following message:
  53. echo '          "shar: End of archive 1 (of 3)."'
  54. if test -f 'README' -a "${1}" != "-c" ; then 
  55.   echo shar: Will not clobber existing file \"'README'\"
  56. else
  57.   echo shar: Extracting \"'README'\" \(1535 characters\)
  58.   sed "s/^X//" >'README' <<'END_OF_FILE'
  59. X"dis" is a SPARC opcode disassembler.  It should work on most SunOS 4.1 and up
  60. Xexecutables and relocatable object files (.o).  I worked from "The SPARC
  61. XArchitecture Reference Manual", version 8, to define the opcodes.
  62. X
  63. XThe entry point to the actual disassembly is in decode.c, "decode_instr()".
  64. Xdecode.c, arithmetic.c, destination.c, memory.c contain all of the real
  65. Xdisassembly code.  The other stuff is a driver routine and fluff to do symbol
  66. Xtable decoding, and debugging info inclusion.
  67. X
  68. XHeadr files arithmetic.h, branches.h, formats.h, memory.h are included by the
  69. Xactual disassembly code files.
  70. X
  71. XIt should be relatively easy to wrap the functions in the 4 .c files listed
  72. Xabove with other drivers to implement other object file formats.
  73. X
  74. XCompile with NOSYNTHETIC defined to reduce/eliminate any
  75. X"synthetic" opcodes in disassembly.
  76. X
  77. XSymbol table and relocation info lookup is done with hash table
  78. Xroutines I got from CAP 2.0, the Columbia Appletalk Package.
  79. XThis part of the program is fairly dependant on the BSD "nlist" format
  80. Xof relocation info, and "stabs" format of symbol table.
  81. XThis part of the code does not lint very cleanly.
  82. X
  83. XIt's only really been used on Suns, SPARC-clones and NeXT 680x0 boxes.
  84. XI have no idea if it's really portable.  After contemplation, I don't
  85. Xbelieve it will work on "little-endian" machines, and I have no idea
  86. Xhow hard it would be to get it to work.  There are an awful lot of
  87. Xassumptions about bit patterns and byte ordering implicit in the
  88. Xstructs used to represent the 32-bit instructions.
  89. X
  90. END_OF_FILE
  91.   if test 1535 -ne `wc -c <'README'`; then
  92.     echo shar: \"'README'\" unpacked with wrong size!
  93.   fi
  94.   # end of 'README'
  95. fi
  96. if test -f 'dis.c' -a "${1}" != "-c" ; then 
  97.   echo shar: Will not clobber existing file \"'dis.c'\"
  98. else
  99.   echo shar: Extracting \"'dis.c'\" \(8549 characters\)
  100.   sed "s/^X//" >'dis.c' <<'END_OF_FILE'
  101. X#include <stdio.h>
  102. X#include <stdlib.h>
  103. X#include <ctype.h>
  104. X#include <string.h>
  105. X#ifdef sparc
  106. X#include <a.out.h>
  107. X#endif
  108. X#include <sys/types.h>
  109. X#include <sys/stat.h>
  110. X#include <fcntl.h>
  111. X#ifndef NeXT
  112. X#include <values.h>
  113. X#endif
  114. X
  115. X#ifndef sun
  116. X#ifdef NeXT
  117. X#include <ansi/m68k/math.h>
  118. X#endif
  119. X#include "sparc_stuff.h"
  120. X#endif
  121. X
  122. Xextern char    *optarg;
  123. Xextern int      optind, opterr;
  124. X
  125. Xint             header, symbolic, line, addresses;
  126. Xint                labels, destinations;
  127. X
  128. X/*
  129. X * main() for SPARC/SunOS 4.1-4.1.2 disassembler
  130. X */
  131. X
  132. Xint
  133. Xmain(c, v)
  134. X    int             c;
  135. X    char          **v;
  136. X{
  137. X    struct exec     exhdr;
  138. X    FILE           *fp_in, *fp_symbol_table;
  139. X    int             n, line_count, unimps_cnt = 0;
  140. X    unsigned long   text_size, instruction_count, current_instr;
  141. X    unsigned long   pc, current_instr_cnt;
  142. X    unsigned long   data_size, data_offset, data_addr;
  143. X    char            opcode_buf[BUFSIZ];
  144. X    char            symbol_name[1024], line_number[1024], *symbol_table_file;
  145. X    char            dest_name[1024];
  146. X    int             printed_symbolic;
  147. X
  148. X    void            usage();
  149. X    char           *decode_instr(), *name_at_address(), *destination_of();
  150. X
  151. X    if (c < 2)
  152. X        usage(*v);
  153. X
  154. X    line = symbolic = header = 1;
  155. X    addresses = 1;
  156. X    labels = destinations = 0;
  157. X    symbol_table_file = NULL;
  158. X    pc = 0xffffffff;
  159. X
  160. X    while ((n = getopt(c, v, "arnlLdb:t:")) != EOF) {
  161. X        switch (n) {
  162. X        case 'r':
  163. X            header = 0;
  164. X            line = symbolic = 0;    /* implied */
  165. X            addresses = 1; labels = 0;
  166. X            break;
  167. X        case 'n':
  168. X            symbolic = 0;
  169. X            break;
  170. X        case 'l':
  171. X            line = 0;
  172. X            break;
  173. X        case 'L':
  174. X            labels = 1;
  175. X            break;
  176. X        case 'a':
  177. X            addresses = 0;
  178. X            break;
  179. X        case 'd':
  180. X            destinations = 1;
  181. X            break;
  182. X        case 'b':
  183. X            /* fill in beginning address for a "raw" disassembly */
  184. X            pc = (unsigned long)strtol(optarg, (char **)NULL, (int)0x10);
  185. X            break;
  186. X        case 't':
  187. X            /* use file optarg as file for symbol table */
  188. X            symbol_table_file = optarg;
  189. X            break;
  190. X        default:
  191. X            usage(*v);
  192. X            break;
  193. X        }
  194. X    }
  195. X
  196. X    /* open input files */
  197. X    if (!strcmp(*(v + optind), "-")) {
  198. X        /* use stdin */
  199. X        fp_in = stdin;
  200. X    } else if ((fp_in = fopen(*(v + optind), "r")) == NULL) {
  201. X        (void) fprintf(stderr, "%s: couldn't open %s for reading \n",
  202. X                   *v, !strcmp(*(v + optind), "-") ? "stdin" : *(v + optind));
  203. X        (void) exit(1);
  204. X    }
  205. X    if (symbol_table_file) {
  206. X        if ((fp_symbol_table = fopen(symbol_table_file, "r")) == NULL) {
  207. X            (void) fprintf(stderr,
  208. X                    "%s: couldn't open %s for reading symbol table\n",
  209. X                    *v, symbol_table_file);
  210. X            line = symbolic = 0;
  211. X        }
  212. X    } else {
  213. X        if (symbolic)
  214. X            fp_symbol_table = fp_in;
  215. X    }
  216. X
  217. X    /* read in header, decide on various sizes and stuff */
  218. X    if (header) {
  219. X        if (fread((char *) &exhdr, sizeof(struct exec), 1, fp_in) == NULL) {
  220. X            (void) fprintf(stderr, "%s: couldn't read %s file header\n",
  221. X                   *v, !strcmp(*(v + optind), "-") ? "stdin" : *(v + optind));
  222. X            exit(1);
  223. X        }
  224. X        if (exhdr.a_machtype != M_SPARC) {
  225. X            (void) fprintf(stderr, "%s: %s isn't a SPARC binary\n",
  226. X                   *v, !strcmp(*(v + optind), "-") ? "stdin" : *(v + optind));
  227. X            exit(2);
  228. X        }
  229. X        text_size = exhdr.a_text;
  230. X        data_size = exhdr.a_data;
  231. X        data_offset = N_DATOFF(exhdr);
  232. X        if (exhdr.a_magic == ZMAGIC)
  233. X            data_addr = N_DATADDR(exhdr);
  234. X        else if (exhdr.a_magic == OMAGIC)
  235. X            data_addr = exhdr.a_entry + exhdr.a_text; /* macro don't work */
  236. X        if (pc == 0xffffffff)
  237. X            pc = exhdr.a_entry; /* initial program counter */
  238. X        if (exhdr.a_magic == ZMAGIC)
  239. X            instruction_count = (text_size - sizeof(struct exec)) / 4;
  240. X        else
  241. X            instruction_count = text_size / 4;
  242. X
  243. X        /* get ready to use symbol table */
  244. X        if (symbolic && !initialize_relocation(&exhdr, fp_symbol_table)) {
  245. X            fprintf(stderr, "failed to initialize relocation info hash table\n");
  246. X            symbolic = 0;
  247. X        }
  248. X        if (line && !initialize_line(&exhdr, fp_in)) {
  249. X            fprintf(stderr, "failed to initialize line number info hash table\n");
  250. X            line = 0;
  251. X        }
  252. X        if (labels) {
  253. X            /* need to scan the instructions for references, forward and back */
  254. X        }
  255. X        fseek(fp_in,
  256. X            (long)(N_TXTOFF(exhdr) +
  257. X            (exhdr.a_magic == ZMAGIC ? sizeof(struct exec) : 0)),
  258. X            0);
  259. X    } else {
  260. X        struct stat     stat_buf;
  261. X        int             fd;
  262. X
  263. X        /*
  264. X         * figure out instruction count for "raw" files, files
  265. X         * without an a.out exec header
  266. X         */
  267. X        if (!strcmp(*(v + optind), "-")) {
  268. X            if ((fd = open(*(v + optind), O_RDONLY)) < 0) {
  269. X                perror("opening input file for fstat()");
  270. X                exit(3);
  271. X            }
  272. X            if (fstat(fd, &stat_buf) < 0) {
  273. X                perror("fstat() of input file failed");
  274. X                exit(4);
  275. X            }
  276. X            instruction_count = stat_buf.st_size / 4;
  277. X        } else {
  278. X            instruction_count = MAXINT;
  279. X        }
  280. X        data_size = 0;
  281. X        if (pc == 0xffffffff) pc = 0;
  282. X        close(fd);
  283. X        if (fp_symbol_table != NULL) {
  284. X            /* despite a "raw" file full of instructions, we have a
  285. X             * symbol table from some other file */
  286. X            if (!initialize_relocation((struct exec *)NULL, fp_symbol_table)) {
  287. X                fprintf(stderr,
  288. X                    "failed to initialize relocation info hash table\n");
  289. X                symbolic = 0;
  290. X            } else symbolic = 1;
  291. X        }
  292. X    }
  293. X
  294. X    /* loop through all the instructions */
  295. X    line_count = 40;
  296. X    for (current_instr_cnt = 1; current_instr_cnt <= instruction_count;
  297. X         ++current_instr_cnt) {
  298. X
  299. X        if (addresses && line_count == 40) {
  300. X            printf("\n\n  Address         Instruction       Decoded\n");
  301. X            line_count = 1;
  302. X        }
  303. X        if (fread((char *) ¤t_instr, sizeof(int), 1, fp_in) == NULL) {
  304. X            if (fp_in != stdin) {
  305. X                (void) fprintf(stderr,
  306. X                   "ran out of file at instruction %d, should be %d instructions\n",
  307. X                           current_instr_cnt, instruction_count);
  308. X                (void) fclose(fp_in);
  309. X                exit(3);
  310. X            } else
  311. X                exit(0);    /* reading from stdin: assume raw object file */
  312. X        }
  313. X        if ((current_instr & 0xffff0000) == 0) {
  314. X            if (unimps_cnt > 0) {
  315. X                ++unimps_cnt;
  316. X                pc += 4;
  317. X                continue;
  318. X            } else {
  319. X                unimps_cnt = 1;
  320. X            }
  321. X        } else {
  322. X            if (unimps_cnt > 0) {
  323. X                if (unimps_cnt > 1)
  324. X                    printf("... a run of %d UNIMPS\n", unimps_cnt);
  325. X                unimps_cnt = 0;
  326. X            }
  327. X        }
  328. X        if (line && line_at_address(pc, line_number) != NULL) {
  329. X            printf("0x%08x   %s\n", pc, line_number);
  330. X        }
  331. X/*
  332. X        NOT IMPLEMENTED YET
  333. X        if (labels && label_at_address(pc)) {
  334. X            printf("L0x%x:\n", pc);
  335. X        }
  336. X*/
  337. X        if (addresses)
  338. X            printf("0x%08x        0x%08x        ", pc, current_instr);
  339. X        else
  340. X            putc('\t', stdout);
  341. X        fputs(decode_instr(current_instr, pc, opcode_buf), stdout);
  342. X        printed_symbolic = 0;
  343. X        if (destinations && destination_of(current_instr, pc, dest_name) != NULL) {
  344. X            if (dest_name[0] != '\0') {
  345. X                printf("\t\t!  %s", dest_name);
  346. X                dest_name[0] = '\0';
  347. X                printed_symbolic = 1;
  348. X            }
  349. X        }
  350. X        if (symbolic && !printed_symbolic && name_at_address(pc, symbol_name) != NULL) {
  351. X            if (symbol_name[0] != '\0') {
  352. X                printf("\t\t!  %s", symbol_name);
  353. X                symbol_name[0] = '\0';
  354. X            }
  355. X        }
  356. X        putc('\n', stdout);
  357. X        ++line_count;
  358. X        opcode_buf[0] = '\0';
  359. X
  360. X        pc += 4;
  361. X    }
  362. X    if (unimps_cnt > 1) {
  363. X        printf("... a run of %d UNIMPS\n", unimps_cnt);
  364. X    }
  365. X
  366. X    if (data_size) {
  367. X        /* try to decode data segment */
  368. X        if (fseek(fp_in, (long)data_offset, 0) < 0) {
  369. X            fprintf(stderr, "couldn't seek to data segment offset %d\n", data_offset);
  370. X        } else {
  371. X            int             ch;
  372. X            void  dump_out(), finish_dumping(), line_break();
  373. X
  374. X            /*
  375. X             * decode the data segment - make it look like "od's"
  376. X             * output, except where it can look like "strings"
  377. X             * output
  378. X             */
  379. X
  380. X            printf("\nData segment deconflation (segment begins at 0x%x)\n\n",
  381. X                data_addr);
  382. X
  383. X            while (data_size && (ch = fgetc(fp_in)) != EOF) {
  384. X                /* do stuff here - address is current */
  385. X                if (symbolic && name_at_address(data_addr, symbol_name) != NULL) {
  386. X                    line_break();
  387. X                    if (symbol_name[0] != '\0') {
  388. X                        printf("0x%08x    symbol  %s\n", data_addr, symbol_name);
  389. X                        symbol_name[0] = '\0';
  390. X                    }
  391. X                }
  392. X
  393. X                dump_out(ch, data_addr);
  394. X                --data_size;
  395. X                ++data_addr;
  396. X            }
  397. X            finish_dumping();
  398. X            putc('\n', stdout);
  399. X        }
  400. X    }
  401. X    (void) fclose(fp_in);
  402. X
  403. X    return(0);
  404. X}
  405. X
  406. Xvoid
  407. Xusage(argv0)
  408. X    char           *argv0;
  409. X{
  410. X    fprintf(stderr, "%s: disassembly of SunOS 4.1 SPARC object code\n", argv0);
  411. X    fprintf(stderr, "usage: %s [-arnlLd] [-b begin addr] [-t symbol table file] input_file\n", argv0);
  412. X    fprintf(stderr, "-r  assume that file has no exec header (raw object file)\n");
  413. X    fprintf(stderr, "-n  make no attempt to discover symbolic names\n");
  414. X    fprintf(stderr, "-l  make no attempt to discover source file line number info\n");
  415. X    fprintf(stderr, "-a  print disassembly without memory addresses\n");
  416. X    fprintf(stderr, "-d  attempt to symbolically indicate branch destinations\n");
  417. X    fprintf(stderr, "-t  filename: get symbol table from \"filename\"\n");
  418. X    fprintf(stderr, "-b  hex address: set initial PC address (useful with raw files)\n");
  419. X
  420. X    exit(1);
  421. X}
  422. END_OF_FILE
  423.   if test 8549 -ne `wc -c <'dis.c'`; then
  424.     echo shar: \"'dis.c'\" unpacked with wrong size!
  425.   fi
  426.   # end of 'dis.c'
  427. fi
  428. if test -f 'hash.3' -a "${1}" != "-c" ; then 
  429.   echo shar: Will not clobber existing file \"'hash.3'\"
  430. else
  431.   echo shar: Extracting \"'hash.3'\" \(17620 characters\)
  432.   sed "s/^X//" >'hash.3' <<'END_OF_FILE'
  433. X.TH hash 3 
  434. X.SH NAME
  435. Xh_new, h_operation, h_free, h_redefine\- manage hash tables
  436. X.SH SYNTAX
  437. X.B #include <sys/types.h>
  438. X.br
  439. X.B #include <hash.h>
  440. X.PP
  441. X.B "caddr_t h_new(policy, htype, M, compare, allocate, compress, \
  442. Xhash, shash, chainops)"
  443. X.br
  444. X.B int policy;
  445. X.br
  446. X.B int htype;
  447. X.br
  448. X.B int M;
  449. X.br
  450. X.B int (\(**compare)();
  451. X.br
  452. X.B caddr_t (\(**allocate)();
  453. X.br
  454. X.B u_int (\(**compress)();
  455. X.br
  456. X.B u_int (\(**hash)();
  457. X.br
  458. X.B u_int (\(**shash)();
  459. X.br
  460. X.B struct hash_bucket_list_ops \(**chainops;
  461. X.PP
  462. X.B "int (\(**compare)(key, data)"
  463. X.br
  464. X.B caddr_t key;
  465. X.br
  466. X.B caddr_t data;
  467. X.PP
  468. X.B "caddr_t (\(**allocate)(p)"
  469. X.br
  470. X.B caddr_t p;
  471. X.PP
  472. X.B u_int (\(**hash)(M, logM, item);
  473. X.br 
  474. X.B int M;
  475. X.br
  476. X.B int logM;
  477. X.br
  478. X.B caddr_t item;
  479. X.PP
  480. X.B u_int (\(**shash)(M, logM, hidx, item);
  481. X.br
  482. X.B int M;
  483. X.br
  484. X.B int logM;
  485. X.br
  486. X.B int hidx;
  487. X.br
  488. X.B caddr_t item;
  489. X.PP
  490. X.B u_int (\(**compress)(item);
  491. X.br
  492. X.B caddr_t item;
  493. X.PP
  494. X.B "caddr_t h_operation(operation, hth, key, bkt, dadvance, distance, bucket)"
  495. X.br
  496. X.B int operation;
  497. X.br
  498. X.B caddr_t hth;
  499. X.br
  500. X.B caddr_t key;
  501. X.br
  502. X.B int bkt;
  503. X.br
  504. X.B int dadvance;
  505. X.br
  506. X.B int \(**distance;
  507. X.br
  508. X.B int \(**bucket;
  509. X.PP
  510. X.B MACRO on h_operation:
  511. X.br
  512. X.B h_member(hth,key)
  513. X.br
  514. X.B caddr_t hth;
  515. X.br
  516. X.B caddr_t key;
  517. X.PP
  518. X.B MACRO on h_operation:
  519. X.br
  520. X.B h_insert(hth, key)
  521. X.br
  522. X.B caddr_t hth;
  523. X.br
  524. X.B caddr_t key;
  525. X.PP
  526. X.B MACRO on h_operation:
  527. X.br
  528. X.B h_delete(hth,key)
  529. X.br
  530. X.B caddr_t hth;
  531. X.br
  532. X.B caddr_t key;
  533. X.PP
  534. X.B "caddr_t h_redefine(hth, policy, htype, M, compare, allocate, \
  535. Xhash, shash, compress, chainops)"
  536. X.br
  537. X.B caddr_t hth;
  538. X.br
  539. X.B int policy;
  540. X.br
  541. X.B int htype;
  542. X.br
  543. X.B int M;
  544. X.br
  545. X.B int (\(**compare)();
  546. X.br
  547. X.B caddr_t (\(**allocate)();
  548. X.br
  549. X.B caddr_t (\(**compress)();
  550. X.br
  551. X.B u_int (\(**hash)();
  552. X.br
  553. X.B u_int (\(**shash)();
  554. X.br
  555. X.B struct hash_bucket_list_ops \(**chainops;
  556. X.PP
  557. X.B MACRO on h_redefine:
  558. X.br
  559. X.B h_rehash(hth,M)
  560. X.br
  561. X.B caddr_t hth;
  562. X.br
  563. X.B int M;
  564. X.PP
  565. X.B "void h_free(hth, free_func)"
  566. X.br
  567. X.B caddr_t hth;
  568. X.br
  569. X.B int (\(**free_func)();
  570. X.PP
  571. X.B int (\(**free_func)(data);
  572. X.br
  573. X.B caddr_t data
  574. X.PP
  575. X.B "struct hash_statistics *h_statistics(hth)"
  576. X.br
  577. X.B caddr_t hth;
  578. X.SH DESCRIPTION
  579. X.I h_new,
  580. X.I h_redefine,
  581. X.I h_free,
  582. Xand
  583. X.I h_operation
  584. Xdefine a general purpose hash table manager that is capable of
  585. Xhandling collision resolution via chaining and open hashing with
  586. Xlinear probing and double probing.
  587. X.PP
  588. X.I h_new
  589. Xis used to create and define the parameters for a hash table.
  590. X.I h_redefine
  591. Xallows you to redefine the hash table parameters.  The
  592. Xassociated macro
  593. X.I h_rehash
  594. Xallows you redefine the size of the table.
  595. X.I h_free
  596. Xis used to free a hash table.
  597. X.PP
  598. X.I h_operation
  599. Xprovides "member", "insert", and "delete" functions for a hash table.
  600. Xh_operation provides a high degree of control to the user.  There are
  601. Xthree associated macros
  602. X.I h_insert,
  603. X.I h_delete,
  604. Xand
  605. X.I h_member
  606. Xthat act as "wrappers" to
  607. X.I h_operation
  608. Xfor
  609. Xsimple operation.
  610. X.SH Creating hash tables
  611. X.I h_new
  612. Xcreates a new hash table and returns a handle that is used to
  613. Xreference it.  The various arguments to h_new define the hash table
  614. Xdefinition (e.g. chaining, open hash, etc) and define some general
  615. Xfunctions necessary for the hashing operations (insert, delete, find).
  616. X.PP
  617. X.I policy
  618. Xdefines how collisions are to be resolved.
  619. X.I HASH_POLICY_CHAIN
  620. Xsays that we should chain off the bucket on a collision.
  621. X.I HASH_POLICY_LINEAR_PROBE
  622. Xresolves collisions with linear probes (e.g. by searching for the next
  623. Xempty hash bucket).
  624. X.I HASH_POLICY_DOUBLE_HASH
  625. Xis like linear probe, but searches in increments given by a
  626. Xsecondary hash function.
  627. XNote that the performance of the non-chain methods degrade severely as
  628. Xthe number of elements in the hash table approach the hash table size.
  629. X.PP
  630. X.I M
  631. Xdefines the minimum hash table size.  For some hash function types, M may be
  632. Xincreased to some prime number or power of 2 larger than the passed
  633. Xvalue.
  634. X.PP
  635. X.I htype
  636. Xdefines the hashing function.  There are a few internally defined
  637. Xhashing functions that may be specified.
  638. X.TP 10
  639. X\fBHASH_TYPE_OWN
  640. Xsays that you will be supplying a
  641. X.I hash
  642. Xfunction and possibly a
  643. X.I shash
  644. Xfunction.  M will be taken as given.  See the discussion of
  645. X.I hash
  646. Xand
  647. X.I shash
  648. Xbelow for more information.
  649. X.TP 10
  650. X\fBHASH_TYPE_DIVISION
  651. Xis the simplest method.  The bucket is choosen on the basis of "key
  652. Xmodulo M".
  653. X.I hash_new
  654. Xresizes the supplied M upwards until it is relatively prime to
  655. X2,3,5,7,11,13,17,19.  It would be best if M was prime such that M does
  656. Xnot divide (size of character set)^b plus/minus a where b and a are
  657. Xsmall numbers; however, choosing M to be relatively prime to the prime
  658. Xfactors less than 20 should still give decent results.
  659. XThe secondary hash for
  660. XHASH_TYPE_DIVISION
  661. Xassumes
  662. Xthat M is prime and uses the function 1 + (K modulo (M - 2)).  Things
  663. Xwill work best if M and M-2 are twin primes like 1021 and 1019.  In
  664. Xgeneral, this will not be true and you should evaluate the
  665. Xeffectiveness on your data.
  666. X(See Knuth, Volume 3 for a full discussion).
  667. X.TP 10
  668. X\fBHASH_TYPE_MULTIPLICATIVE
  669. Xforces up the passed M so that it is a power of 2 (call it 2^r).
  670. XThe hash function used is AK>>(number of bits in a word - r) where A
  671. Xis an integer constant relatively prime to 2^32 (for a 32 bit
  672. Xmachine).
  673. XA has been chosen to attempt fibonacci
  674. Xhashing (whether this holds or not is debatable--futher research
  675. Xrequired).  See A_MULTIPLIER in hash.h.
  676. XThe secondary hash function takes r higher bits in the product defined
  677. Xabove and oring in a one (e.g. right shifts number of bits - 2*r).
  678. X(See Knuth, Volume 3, for a full discussion).
  679. X.PP
  680. XThe
  681. X.I compare
  682. Xfunction is a required user specified routine to compare a key (key) to a
  683. Xstored data item (data).
  684. XIt should return negative, zero, or positive if the comparision is
  685. Xless than, equal to, or greater than respectively.
  686. X.PP
  687. XThe
  688. X.I allocate
  689. Xfunction allows one to insert data through
  690. X.I h_operation
  691. Xwithout allocating it before hand.
  692. XIf
  693. X.I allocate
  694. Xis not given, it assume that the key is the data.
  695. X.PP
  696. X.I hash,
  697. Xif non-null, defines the primary hash function that is used to compute
  698. Xthe bucket corresponding to the key.
  699. X.I shash,
  700. Xif non-null, defines the secondary hash function used to obtain a
  701. X"movement" value for collision resolution for the open hash policies.
  702. XIt is worth noting
  703. Xthat 
  704. X.I shash,
  705. Xif specified, will be used by linear probing.
  706. XSpecifying linear
  707. Xprobing versus double probing matters when no secondary hash function
  708. Xis given.
  709. XThe arguments to
  710. X.I hash
  711. Xare the size of the hash
  712. Xtable, the log base 2 of the size of the hash table (not the floor
  713. Xlog2(M), but 2^r s.t. 2^r >= M), and the key K.
  714. X.I shash
  715. Xalso takes as a parameter (hidx) the value return by
  716. X.I hash.
  717. XSpecification of the hash functions will override any specified by the
  718. Xhash type argument; however, the passed value of M will still be
  719. Xresized according to the passed hash type (e.g. for multiplicative,
  720. XM will be bumped until it is a power of 2).
  721. X.PP
  722. X.I compress
  723. Xis used to compress a coerce a key to an unsigned
  724. Xinteger for the hash functions and to dereference the data pointed to by
  725. Xkey (which usually is a pointer).
  726. XIt is generally required
  727. Xfor internal hashing
  728. Xfunctions are used and optional otherwise (though your hash function
  729. Xwould have to do the compression if you don't supply this routine).
  730. XAn example of a compress function for an
  731. Xstring would be:
  732. X.nf
  733. X    compress(s) unsigned char *s; 
  734. X    {
  735. X      unsigned int j = 0;
  736. X      while (*s) j += *s++;
  737. X    }
  738. X.fi
  739. XIn this case, it is important to note that a simpler function like an
  740. Xxor across the
  741. Xdata will make the range too small (unless the table is very small)
  742. Xbecause you would only be making use of 8 bits for a maximum hash
  743. Xrange of 256.
  744. X(Note: this
  745. Xcompression function is only so-so, it would be better if it rotated
  746. Xthe data on every turn to ensure that all the bits come fully into
  747. Xplay--however, this is highly dependent upon the data the hashing
  748. Xtype).  Note, if you don't supply a compression function (e.g. specify
  749. Xas NULL), then the key will be used directly.
  750. XThis will cause
  751. Xproblems if sizeof(caddr_t) != sizeof(unsigned int), so consider this
  752. Xcarefully (i.e. don't do it -- pass a pointer to a variable containing
  753. Xthe key and write a dummy compress function that just returns the value).
  754. X.PP
  755. X.I chainops
  756. Xwill be describe in a later section in full detail.  Essentially, it
  757. Xallows one to chain off the buckets in an arbritrary fashion (perhaps
  758. Xwith another hash table).  By default, it is done with an ordered linked
  759. Xlist.  Of course, it is only meanful when the policy selected is chain.
  760. X.PP
  761. X.I h_redefine
  762. Xtakes the hash table handle as an argument in addition to all the
  763. Xother arguments of 
  764. X.I h_new.  
  765. X.I h_redefine
  766. Xwill reformat the hash table
  767. Xaccording to the passed arguments.  It will rehash if the hash table
  768. Xis valid (so it should not be called lightly).
  769. X.I WARNING:
  770. XIf you want to use h_redefine, it is important that the "key" as
  771. Xpassed to the 
  772. X.I h_operation
  773. Xroutines is the same as the data stored in the buckets!  
  774. XThis is necessary because
  775. X.I h_redefine
  776. Xoperates by calling
  777. X.I h_insert
  778. Xwith the items in the buckets as the key.
  779. X.PP
  780. X.I policy
  781. Xand 
  782. X.I type
  783. Xcan be
  784. Xspecified as 
  785. X.I HASH_POLICY_OLD
  786. Xand
  787. X.I HASH_TYPE_OLD respectively to retain
  788. Xthe old policy and type.  For 
  789. X.I compare, 
  790. X.I allocate, 
  791. X.I hash, 
  792. X.I shash,
  793. X.I compress, and 
  794. X.I chainops,
  795. Xpass NULL unless you wish to change those functions.  Set M
  796. Xto be zero to retain the old table size (note, if a new hash type is
  797. Xspecified, the passed M may be resized).  It is expected that the main use
  798. X.I h_redefine
  799. Xwill be to increase the hash table size: use the macro 
  800. X.I h_rehash
  801. Xfor this.
  802. X.PP
  803. X.I h_free
  804. Xwill free a hash table.  It calls
  805. X.I free_func
  806. Xon every item inserted into the table so that data can be released if
  807. Xnecessary.  If free_func is NULL, then it is assumed that the data
  808. Xneed not be released.
  809. X.SH Hash Operations
  810. X.I h_operation
  811. Xprovides insert, member, and delete operations on a hash table created
  812. Xby h_new.  A high degree of control over its operation is provided.
  813. XThe macros
  814. X.I h_insert,
  815. X.I h_delete,
  816. Xand
  817. X.I h_member
  818. Xhide the less commonly used arguments.
  819. X.PP
  820. X.I operation 
  821. Xdefines the operation to be performed.  It best if
  822. X.I key
  823. Xis a pointer to data instead of the actual key.
  824. X.TP 10
  825. X\fB HASH_OP_MEMBER
  826. Xfinds an item based upon
  827. X.I key
  828. Xand returns it.  If the item is not
  829. Xin the table, NULL is returned.
  830. XThe comparision function defined in 
  831. X.I h_new
  832. Xis used to determine if the
  833. Xitem is in the table.
  834. X.TP 10
  835. X\fBHASH_OP_INSERT
  836. Xis like find, but the item is inserted if it wasn't already in the
  837. Xtable.
  838. X.I allocate,
  839. Xif non-null,
  840. Xas defined in
  841. X.I h_new
  842. Xis called to get the data to be stored.  If
  843. X.I allocate
  844. Xis NULL, then it assumed that the key is the data.
  845. XNULL is returned if the item could not be inserted because all the
  846. Xbuckets were filled or a memory allocation failed.
  847. X.TP 10
  848. X\fB HASH_OP_DELETE
  849. Xwill remove the specified item from the table and return it
  850. Xif it was in the table.
  851. XNULL will be returned if the item was not in the
  852. Xtable.
  853. X.PP
  854. X.I hth
  855. Xis the hash table handle as returned by
  856. X.I h_new.
  857. X.PP
  858. X.I key
  859. Xis the used to match the data in the table.
  860. XNormally it is a pointer to some data item.
  861. X.PP
  862. X.I bkt,
  863. Xand
  864. X.I dadvance
  865. Xallow you to specify the hash bucket to use and the 
  866. Xhash advance (default is 1) to use in open hashing collision
  867. Xresolution respectively.
  868. XIf
  869. Xthese are specified as negative numbers, the hash functions
  870. Xdefined in
  871. X.I h_new
  872. Xwill be used.
  873. X.PP
  874. X.I bucket
  875. Xshould be a pointer to an integer into which the primary bucket will
  876. Xbe returned (e.g. the index returned by primary hash function).
  877. X.I distance
  878. Xis set to the number of buckets examined (beyond the first one) before
  879. Xthe item as added.
  880. X.SH Chaining off buckets
  881. XThe default action for chaining off a bucket is to use a linked list
  882. Xordered largest to smallest (as defined by the comparision function).
  883. XIt is possible to define an arbitrary method by defining a set of
  884. Xchain operations.  The functions needed are defined below and should be put 
  885. Xin a struct hash_bucket_list_ops and passed upon a hash table create.
  886. X.nf
  887. X    struct hash_bucket_list_ops {
  888. X      caddr_t (*hlo_find)();
  889. X      caddr_t (*hlo_insert)();
  890. X      int (*hlo_delete)();
  891. X      caddr_t (*hlo_get)();    /* get any and remove */
  892. X    };
  893. X.fi
  894. X.PP
  895. XIn the following discussion, 
  896. X.I bp
  897. Xis where information about the "list"
  898. Xis stored.  "list" is used to mean your storage mechanism.  It could
  899. Xbe linked list, hash table, array, etc.
  900. X.I bp
  901. Xallows you to disambiguate which list--unless your hash table size is
  902. Xone, you must support more than one list.  An item in the following is
  903. Xan abstract entity that can be compared against a key by the
  904. X.I compare
  905. Xfunction provided in
  906. X.I h_new.
  907. X.I hlo_find,
  908. X.I hlo_insert,
  909. Xand
  910. X.I hlo_delete
  911. Xare matched functions.
  912. X.I hlo_find
  913. Xis always called before
  914. X.I hlo_insert
  915. Xor
  916. X.I hlo_delete
  917. Xand the hash table functions will only call insert or delete if the
  918. Xitem (defined by the key) is not in the list
  919. Xand in the list respectively.
  920. X.PP
  921. X.nf
  922. Xcaddr_t (*hlo_find)(bp, key, cmp, distance, hint, hint2)
  923. Xcaddr_t bp;
  924. Xcaddr_t key;
  925. Xint (*cmp)();
  926. Xint *distance;
  927. Xcaddr_t *hint;
  928. Xcaddr_t *hint2;
  929. X.fi
  930. X.I hlo_find
  931. Xis used to see if the specified item is in the list based upon the
  932. Xkey.  It should return
  933. Xthe the item stored in the list if there and NULL
  934. Xotherwise.  If non-null, this is the value that will be returned by
  935. X.I h_operation.
  936. XIf the return value will be non-null, then
  937. X.I distance
  938. Xshould be set to
  939. Xsome metric by this function (e.g. distance from head of list on
  940. Xlinked list).  
  941. X.I cmp
  942. Xis a comparision function to use (as passed in h_new).
  943. X.I hint,
  944. Xand
  945. X.I hint2
  946. Xare places to store hints for
  947. X.I hlo_insert
  948. Xand
  949. X.I hlo_delete.
  950. X.PP
  951. X.nf
  952. Xcaddr_t (*hlo_insert)(bp, key, allocate, distance, hint, hint2)
  953. Xcaddr_t *bp;
  954. Xcaddr_t key;
  955. Xcaddr_t (*allocate)();
  956. Xint *distance;
  957. Xcaddr_t hint1;
  958. Xcaddr_t hint2;
  959. X.fi
  960. X.I hlo_insert
  961. Xshould insert an item onto the list.  It should call
  962. X.I allocate,
  963. Xif defined, to create the item based upon the key.  The distance should
  964. Xbe updated with respect to your metric set.
  965. X.I hint,
  966. Xand
  967. X.I hint2
  968. Xare passed as set by the
  969. X.I hlo_find.
  970. XYou should set the bucket pointer to point to your "list" if the list
  971. Xwas empty before (e.g. *bp = head_of_list, *bp = hash_table_handle,
  972. Xetc.).
  973. X.I hlo_insert
  974. Xshould return the stored data.  If it cannot insert the
  975. Xitem it may return NULL
  976. X.I hlo_insert's
  977. Xvalue will be the value
  978. Xreturned by 
  979. X.I hlo_operation.
  980. X.PP
  981. X.nf
  982. Xint (*hlo_delete)(bp, key, distance, hint, hint2)
  983. Xcaddr_t *bp;
  984. Xcaddr_t key;
  985. Xint *distance;
  986. Xcaddr_t hint;
  987. Xcaddr_t hint2;
  988. X.fi
  989. X.I hlo_delete
  990. Xshould remove the specified item from the list.  It should return TRUE
  991. Xon success and FALSE on failure.  distance should be set to the
  992. Xdistance of the deleted item with respect to the arbritry metric
  993. Xdefined for your set of functions.  The bucket pointer should be set
  994. Xto NULL if there are no longer items in the list (e.g. *bp = NULL).
  995. X.I hint
  996. Xand
  997. X.I hint2
  998. Xare passed as set by the last 
  999. X.I hlo_find
  1000. Xoperation.
  1001. X.PP
  1002. X.nf
  1003. Xcaddr_t (*hlo_get)(bp)
  1004. Xcaddr_t *bp;
  1005. X.fi
  1006. X.I hlo_get
  1007. Xis used by the
  1008. X.I h_redefine
  1009. Xand
  1010. X.I h_free
  1011. Xfunctions.
  1012. XIt should unlink an abritrary item from the list and return it.
  1013. X.PP
  1014. XThe following simple set of functions define a hash table with no
  1015. Xcollisions allowed:
  1016. X.nf
  1017. X    none_find(bp, key, cmp, distance, hint, hint2)
  1018. X    caddr_t bp, key, *hint,*hint2;
  1019. X    int (*cmp)(), *distance;
  1020. X    {
  1021. X      *distance = 0;
  1022. X      if (bp == NULL)    /* nothing in list */
  1023. X        return(NULL);
  1024. X      if ((*cmp)(key,bp) == 0)
  1025. X        return(*bp);
  1026. X    }
  1027. X
  1028. X    caddr_t none_insert(bp, key, allocate, distance, hint, hint2)
  1029. X    caddr_t *bp, key, *hint,*hint2;
  1030. X    caddr_t (*dup)();
  1031. X    {
  1032. X      *distance = 0;
  1033. X      *bp = allocate ? (*allocate)(key) : key;
  1034. X    }
  1035. X
  1036. X    int none_delete(bp, key, distance, hint, hint2)
  1037. X    caddr_t *bp, key, *hint,*hint2;
  1038. X    {
  1039. X      caddr_t v = *bp;
  1040. X      *distance = 0;
  1041. X      return(v != NULL);    /* true if we deleted */
  1042. X    }
  1043. X
  1044. X    caddr_t none_get(bp)
  1045. X    caddr_t *bp;
  1046. X    {
  1047. X      caddr_t r = *bp;
  1048. X      *bp = NULL;
  1049. X      return(r);
  1050. X    }
  1051. X.fi
  1052. X.SH Statisitcs
  1053. X.I h_statistics
  1054. Xreturns a pointer to the following structure:
  1055. X.nf
  1056. X    struct hash_statistics {
  1057. X      int hs_buckets;    /* number of buckets in table */
  1058. X      /* describes # of entries in chain */    
  1059. X      int hs_used;        /* # of buckets filled */
  1060. X      /* describes table (not accurate for chain policy) */
  1061. X      int hs_davg;        /* average distance from hash */
  1062. X      int hs_dsum;        /* sum of distances from hash */
  1063. X      int hs_dmax;        /* maximum distance from hash */
  1064. X      /* describes lookup patterns (describes distance into */
  1065. X      /* linear table if the policy is chain */
  1066. X      int hs_lnum;        /* remember number of lookups */
  1067. X      int hs_lsum;        /* sum of lookup distances */
  1068. X      int hs_lavg;        /* average lookup distance */
  1069. X      /* cumulative for lookup patterns (describes overall */
  1070. X      /* efficiency) */
  1071. X      int hs_clnum;        /* remember number of lookups */
  1072. X      int hs_clsum;        /* sum of lookup distances */
  1073. X    };
  1074. X.fi
  1075. XThe averages are reported as a fixed point number with two decimal
  1076. Xdigits of precision after the decimal point (e.g. avg/100.avg%100).
  1077. X.PP
  1078. XThe lookup and table statistics are cleared on a
  1079. X.I h_redefine
  1080. Xoperation.
  1081. X.SH NOTES
  1082. XSome analysis of the hashing functions provided should be done to
  1083. Xdetermine how "good" they are.
  1084. X.br
  1085. XAllocate probably should have been called "get_item" in the above.
  1086. X.br
  1087. XPossibly some method for returning the "nth" or "next" item in the
  1088. Xhash table should be provided for times when it is necessary to access
  1089. Xthe items in a linear fashion.  However, it possible to do this
  1090. Xalready using the "allocate" call to put the items on a linked list or
  1091. Xin an array.
  1092. X.SH RESTRICTIONS
  1093. XPerhaps more control over the hashing functions should be provided;
  1094. Xhowever, it is easy enough to replace them.
  1095. X.SH REFERENCES
  1096. XSearching and Sorting, The Art of Computer Programming, Volume 3,
  1097. XDonald E. Knuth.
  1098. X.SH "SEE ALSO"
  1099. Xbsearch(3), lsearch(3), string(3), tsearch(3), hsearch(3)
  1100. X
  1101. X
  1102. END_OF_FILE
  1103.   if test 17620 -ne `wc -c <'hash.3'`; then
  1104.     echo shar: \"'hash.3'\" unpacked with wrong size!
  1105.   fi
  1106.   # end of 'hash.3'
  1107. fi
  1108. if test -f 'hash.c' -a "${1}" != "-c" ; then 
  1109.   echo shar: Will not clobber existing file \"'hash.c'\"
  1110. else
  1111.   echo shar: Extracting \"'hash.c'\" \(21202 characters\)
  1112.   sed "s/^X//" >'hash.c' <<'END_OF_FILE'
  1113. Xstatic char rcsid[] = "$Author: djh $ $Date: 91/02/15 23:07:35 $";
  1114. Xstatic char rcsident[] = "$Header: hash.c,v 2.1 91/02/15 23:07:35 djh Rel $";
  1115. Xstatic char revision[] = "$Revision: 2.1 $";
  1116. X
  1117. X/*
  1118. X * hash.h - external definitions for hash.c - generalized hashing function
  1119. X *
  1120. X *  written by Charlie C. Kim
  1121. X *     Academic Networking, Communications and Systems Group
  1122. X *     Center For Computing Activities
  1123. X *     Columbia University
  1124. X *   September 1988
  1125. X *
  1126. X *
  1127. X * Copyright (c) 1988 by The Trustees of Columbia University 
  1128. X *  in the City of New York.
  1129. X *
  1130. X * Permission is granted to any individual or institution to use,
  1131. X * copy, or redistribute this software so long as it is not sold for
  1132. X * profit, provided that this notice and the original copyright
  1133. X * notices are retained.  Columbia University nor the author make no
  1134. X * representations about the suitability of this software for any
  1135. X * purpose.  It is provided "as is" without express or implied
  1136. X * warranty.
  1137. X *
  1138. X *
  1139. X * Edit History:
  1140. X *
  1141. X *  Sept 5, 1988  CCKim Created
  1142. X *  Sept 6, 1988  CCKim Finished: level 0
  1143. X *
  1144. X*/
  1145. X
  1146. Xstatic char columbia_copyright[] = "Copyright (c) 1988 by The Trustees of \
  1147. XColumbia University in the City of New York";
  1148. X
  1149. X#include <stdio.h>
  1150. X#include <sys/types.h>
  1151. X#include "hash.h"
  1152. X
  1153. X#ifndef FALSE
  1154. X# define FALSE 0
  1155. X#endif
  1156. X#ifndef TRUE
  1157. X# define TRUE 1
  1158. X#endif
  1159. X#ifndef PRIVATE
  1160. X# define PRIVATE static
  1161. X#endif
  1162. X
  1163. X
  1164. X/*
  1165. X * holds and describes a hash table
  1166. X *
  1167. X * ht_policy: policy on collisions (cf hash.h)
  1168. X * ht_cfunc: takes (key, data) and returns true if they are equal
  1169. X * ht_afunc: takes a key and returns the item from higher up
  1170. X * ht_cpfunc: should compress the key to a integer -- only required if
  1171. X *    no hash function has been provided
  1172. X * ht_hfunc: takes (M, data) as arguments - returns hash index
  1173. X *    M is the sizeof(int)*8 - log of the table size if the hashing
  1174. X *     type is multiplicative
  1175. X * ht_hfunc2: is the secondary hashing function for double hashing
  1176. X * ht_chainops: chaining function other than linked list
  1177. X * ht_stats: describes performance of hash table
  1178. X * ht_type: hash function type
  1179. X * ht_buckets: pointer to the hash table buckets
  1180. X *
  1181. X*/
  1182. Xtypedef struct htable {
  1183. X  int ht_M;            /* # of hash table buckes */
  1184. X  int ht_logM;            /* M or log M (for certain hash types) */
  1185. X  int ht_policy;        /* hashing policies for collision */
  1186. X  /* alway call with passed key first, data item second */
  1187. X  int (*ht_cfunc)();        /* comparision function */
  1188. X  caddr_t (*ht_afunc)();    /* allocate function */
  1189. X  u_int (*ht_cpfunc)();        /* compression function */
  1190. X  u_int (*ht_hfunc)();        /* hashing function */
  1191. X  u_int (*ht_hfunc2)();        /* secondary hashing function */
  1192. X  struct hash_bucket_list_ops *ht_chainops; /* chain functions */
  1193. X  int ht_type;            /* hash type */
  1194. X  struct hash_statistics ht_stats; /* statisitics */
  1195. X  caddr_t *ht_buckets;        /* actual hash table */
  1196. X} HTABLE;
  1197. X
  1198. X/* some hash functions */
  1199. XPRIVATE u_int hash_multiplicative();
  1200. XPRIVATE u_int hash_division();
  1201. XPRIVATE u_int hash2_multiplicative();
  1202. XPRIVATE u_int hash2_division();
  1203. X
  1204. X/* list operations */
  1205. XPRIVATE caddr_t list_find();
  1206. XPRIVATE caddr_t list_insert();
  1207. XPRIVATE int list_delete();
  1208. XPRIVATE caddr_t list_get();
  1209. X
  1210. X/* basic hash bucket chaining with an ordered link list */
  1211. XPRIVATE struct hash_bucket_list_ops hash_chain_by_list = {
  1212. X  list_find,
  1213. X  list_insert,
  1214. X  list_delete,
  1215. X  list_get
  1216. X};
  1217. X
  1218. X/* table of primary hashfunctions */
  1219. XPRIVATE u_int (*hash_funcs[HASH_TYPE_NUM])() = {
  1220. X  NULL,
  1221. X  hash_division,
  1222. X  hash_multiplicative,
  1223. X};
  1224. X
  1225. X/* table of secondary hash functions */
  1226. XPRIVATE u_int (*hash_funcs2[HASH_TYPE_NUM])() = {
  1227. X  NULL,                /* own */
  1228. X  hash2_division,
  1229. X  hash2_multiplicative,
  1230. X};
  1231. X
  1232. X/* free a hash table - free_func gets called to free data */
  1233. Xvoid
  1234. Xh_free(ht, free_func)
  1235. XHTABLE *ht;
  1236. Xint (*free_func)();
  1237. X{
  1238. X  caddr_t *bt;
  1239. X  caddr_t p;
  1240. X  int M, i, policy;
  1241. X  caddr_t (*get_func)();
  1242. X  
  1243. X  M = ht->ht_M;            /* get # of entries */
  1244. X  bt = ht->ht_buckets;        /* get buckets */
  1245. X  ht->ht_buckets = NULL;    /* just in case... */
  1246. X  if (ht->ht_chainops)
  1247. X    get_func = ht->ht_chainops->hlo_get;
  1248. X  policy = ht->ht_policy;
  1249. X  if (bt == NULL)
  1250. X    return;
  1251. X  for (i = 0; i < M; i++) {
  1252. X    if (bt[i] == NULL)
  1253. X      continue;
  1254. X    switch (policy) {
  1255. X    case HASH_POLICY_CHAIN:
  1256. X      if (get_func == NULL)
  1257. X    break;
  1258. X      while ((p = (*get_func)(&bt[i])))
  1259. X    if (free_func)
  1260. X      (*free_func)(p);
  1261. X      break;
  1262. X    default:
  1263. X    if (free_func)
  1264. X      (*free_func)(bt[i]);
  1265. X    }
  1266. X  }
  1267. X  free((caddr_t)bt);            /* free old table */
  1268. X  free((caddr_t)ht);
  1269. X}
  1270. X
  1271. X/* setup a new hash table, returns handle for hash table */
  1272. Xcaddr_t
  1273. Xh_new(policy, hashtype, M, cfunc, afunc, cpfunc, hfunc, hfunc2, chainops)
  1274. Xint policy;
  1275. Xint hashtype;            /* hash type */
  1276. Xint M;
  1277. Xint (*cfunc)();            /* comparision function */
  1278. Xcaddr_t (*afunc)();            /* allocate function */
  1279. Xu_int (*cpfunc)();        /* compression function */
  1280. Xu_int (*hfunc)();        /* hash function */
  1281. Xu_int (*hfunc2)();        /* secondary hash function */
  1282. Xstruct hash_bucket_list_ops *chainops;
  1283. X{
  1284. X  HTABLE *htable;
  1285. X
  1286. X  if (cfunc == NULL) {        /* required! */
  1287. X    fprintf(stderr, "hash table create: no compare function\n");
  1288. X    return(NULL);
  1289. X  }
  1290. X  if (!HASH_TYPE_VALID(hashtype)) {
  1291. X    fprintf(stderr, "hash table create: invalid type %d\n", hashtype);
  1292. X    return(NULL);
  1293. X  }
  1294. X  if (hashtype == HASH_TYPE_OWN && hfunc == NULL) {
  1295. X  fprintf(stderr, "hash table create: must give hash function when own set\n");
  1296. X  return(NULL);
  1297. X  }
  1298. X  if (!HASH_POLICY_VALID(policy)) {
  1299. X    fprintf(stderr, "hash table create: invalid policy %d\n", policy);
  1300. X    return(NULL);
  1301. X  }
  1302. X  if (M <= 0) {
  1303. X    fprintf(stderr, "hash table create: invalid hash table size %d\n", M);
  1304. X    return(NULL);
  1305. X  }
  1306. X  if ((htable = (HTABLE *)malloc(sizeof(HTABLE))) == NULL)
  1307. X    return(NULL);
  1308. X  htable->ht_policy = policy;
  1309. X  htable->ht_cfunc = cfunc;
  1310. X  htable->ht_afunc = afunc;
  1311. X  htable->ht_hfunc = hash_funcs[hashtype];
  1312. X  if (htable->ht_policy == HASH_POLICY_DOUBLE_HASH)
  1313. X    htable->ht_hfunc2 = hash_funcs2[hashtype];
  1314. X  else
  1315. X    htable->ht_hfunc2 = NULL;
  1316. X  /* override std. hash functions if specified */
  1317. X  if (hfunc)
  1318. X    htable->ht_hfunc = hfunc;
  1319. X  if (hfunc2)
  1320. X    htable->ht_hfunc2 = hfunc2;
  1321. X  htable->ht_cpfunc = cpfunc;
  1322. X  htable->ht_chainops = chainops ? chainops : &hash_chain_by_list;
  1323. X  htable->ht_type = hashtype;
  1324. X  bzero(&htable->ht_stats, sizeof(htable->ht_stats));
  1325. X  htable->ht_stats.hs_buckets = M;
  1326. X  htable->ht_M = 0;        /* assume these */
  1327. X  return((caddr_t)h_redefine(htable,HASH_POLICY_OLD,HASH_TYPE_OLD, M,
  1328. X                 NULL, NULL,NULL,NULL, NULL, NULL));
  1329. X}
  1330. X
  1331. X/* redefine an existing hash table, will rehash by creating new set of */
  1332. X/* buckets and killing off old set */
  1333. Xcaddr_t
  1334. Xh_redefine(ht, policy, hashtype, M, cfunc, afunc, cpfunc, hfunc, hfunc2,
  1335. X       chainops)
  1336. XHTABLE *ht;
  1337. Xint policy;            /* hashing policy */
  1338. Xint hashtype;            /* hashing type */
  1339. Xint M;                /* size */
  1340. Xint (*cfunc)();            /* comparision function */
  1341. Xcaddr_t (*afunc)();        /* allocate function */
  1342. Xu_int (*hfunc)();        /* hash function */
  1343. Xu_int (*hfunc2)();        /* secondary hash function */
  1344. Xu_int (*cpfunc)();        /* compression function */
  1345. Xstruct hash_bucket_list_ops *chainops;
  1346. X{
  1347. X  int logM, oldM, i, oldPolicy;
  1348. X  struct hash_bucket_list_ops *oldChainOps;
  1349. X  caddr_t *bt, *nbt;
  1350. X  caddr_t p;
  1351. X
  1352. X  if (!HASH_TYPE_VALID(hashtype) && hashtype != HASH_TYPE_OLD) {
  1353. X    fprintf(stderr, "hash table create: invalid type %d\n", hashtype);
  1354. X    return(NULL);
  1355. X  }
  1356. X  if (!HASH_POLICY_VALID(policy) && policy != HASH_POLICY_OLD) {
  1357. X    fprintf(stderr, "hash table create: invalid policy %d\n", policy);
  1358. X    return(NULL);
  1359. X  }
  1360. X  if (M <= 0)            /* zero means base on old */
  1361. X    M = ht->ht_M;
  1362. X  if (hashtype == HASH_TYPE_OLD)
  1363. X    hashtype = ht->ht_type;    /* get old */
  1364. X  logM = 0;
  1365. X  switch (hashtype) {
  1366. X  case HASH_TYPE_MULTIPLICATIVE:
  1367. X    i = M >> 1;
  1368. X    M = 1;
  1369. X    logM = 0;
  1370. X    while (i) {            /* while M is still about */
  1371. X      i >>= 1;            /* divide by 2 */
  1372. X      M <<= 1;            /* multiply by 2 */
  1373. X      logM++;
  1374. X    }
  1375. X    break;
  1376. X  case HASH_TYPE_DIVISION:
  1377. X    M += (1 - (M%2));        /* make odd */
  1378. X    /* scale up M so it isn't relatively prime for these small primes */
  1379. X    /* c.f. Fundamental of Data Structures, Horowitz and Sahni, pp. 461 */
  1380. X    while (!((M%3) && (M%5) && (M%7) && (M%11) && (M%13) && (M%17)&&(M%19)))
  1381. X      M+=2;
  1382. X    break;
  1383. X  default:
  1384. X    break;
  1385. X  }
  1386. X  if (M <= ht->ht_M)        /* nothing to do */
  1387. X    return((caddr_t)ht);
  1388. X  if (logM == 0) {        /* no logM?  figure it */
  1389. X    int t = M>>1;        /* get M */
  1390. X    do {
  1391. X      logM++;            /* int log M to 1 */
  1392. X      t >>= 1;            /* divide by 2 */
  1393. X    } while (t);
  1394. X  }
  1395. X  bt = ht->ht_buckets;        /* get buckets */
  1396. X  oldM = ht->ht_M;
  1397. X  oldPolicy = ht->ht_policy;
  1398. X  oldChainOps = ht->ht_chainops;
  1399. X
  1400. X  if ((nbt = (caddr_t *)calloc((u_int)M, sizeof(caddr_t))) == NULL) {
  1401. X    fprintf(stderr, "hash table create: no memory for %d element table\n",M);
  1402. X    return(NULL);        /* return */
  1403. X  }
  1404. X  ht->ht_buckets = nbt;    /* save new bucket table */
  1405. X  ht->ht_M = M;        /* assume these */
  1406. X  ht->ht_logM = logM;
  1407. X  ht->ht_stats.hs_buckets = M; /* mark # of buckets */
  1408. X  ht->ht_policy = (policy == HASH_POLICY_OLD) ? oldPolicy : policy;
  1409. X  if (afunc)
  1410. X    ht->ht_afunc = afunc;
  1411. X  if (cfunc)
  1412. X    ht->ht_cfunc = cfunc;
  1413. X  if (ht->ht_type != hashtype && hashtype != HASH_TYPE_OLD) {
  1414. X    ht->ht_hfunc = hash_funcs[hashtype];
  1415. X    if (ht->ht_policy == HASH_POLICY_DOUBLE_HASH)
  1416. X      ht->ht_hfunc2 = hash_funcs2[hashtype];
  1417. X    else
  1418. X      ht->ht_hfunc2 = NULL;
  1419. X  }
  1420. X  /* always reset if given */
  1421. X  if (hfunc)
  1422. X    ht->ht_hfunc = hfunc;
  1423. X  if (hfunc2)
  1424. X    ht->ht_hfunc2 = hfunc2;
  1425. X  if (cpfunc)
  1426. X    ht->ht_cpfunc = cpfunc;
  1427. X  if (chainops)
  1428. X    ht->ht_chainops = chainops;
  1429. X  ht->ht_type = hashtype;
  1430. X  {
  1431. X    struct hash_statistics *s = &ht->ht_stats;
  1432. X    /* no longer valid */
  1433. X    s->hs_used = s->hs_davg = s->hs_dsum = s->hs_dmax = 0;
  1434. X    /* no longer valid */
  1435. X    s->hs_lnum = s->hs_lsum = s->hs_lavg = 0;
  1436. X    /* cum. statistics stay */
  1437. X  }
  1438. X  /* rehash if new table */
  1439. X  if (bt) {
  1440. X    afunc = ht->ht_afunc;    /* save */
  1441. X    ht->ht_afunc = NULL;        /* turn off for a bit */
  1442. X    for (i = 0; i < oldM; i++) {
  1443. X      if (bt[i]) {
  1444. X    switch (oldPolicy) {
  1445. X    case HASH_POLICY_CHAIN:
  1446. X      while ((p = (*oldChainOps->hlo_get)(&bt[i])))
  1447. X        h_insert(ht, p);
  1448. X      break;
  1449. X    default:
  1450. X      h_insert(ht, bt[i]);
  1451. X    }
  1452. X      }
  1453. X    }
  1454. X    ht->ht_afunc = afunc;    /* turn back on */
  1455. X    free((caddr_t)bt);        /* free old table */
  1456. X  }
  1457. X  return((caddr_t)ht);
  1458. X}
  1459. X
  1460. X/* update hash TABLE statistics: generally, these are off for chain */
  1461. X/* and when there are deletes done */ 
  1462. XPRIVATE int
  1463. Xupdate_hash_table_stats(s, distance, updown)
  1464. Xstruct hash_statistics *s;
  1465. Xint distance;
  1466. Xint updown;
  1467. X{
  1468. X  if (distance > s->hs_dmax) /* new maximum distance */
  1469. X    s->hs_dmax = distance;
  1470. X  s->hs_dsum += distance;    /* bump sum of distances */
  1471. X  s->hs_used += updown;
  1472. X  if (s->hs_used)
  1473. X    s->hs_davg = (100*s->hs_dsum) / s->hs_used; /* scale it */
  1474. X  else
  1475. X    s->hs_davg = 0;
  1476. X  return(s->hs_davg);
  1477. X}
  1478. X
  1479. X/* update lookup statisitics */
  1480. XPRIVATE int
  1481. Xupdate_hash_lookup_stats(s, distance)
  1482. Xstruct hash_statistics *s;
  1483. Xint distance;
  1484. X{
  1485. X  s->hs_lsum += distance;    /* bump sum of distances */
  1486. X  s->hs_lnum++;            /* bump number of distances */
  1487. X  s->hs_clsum += distance;    /* same for cum. */
  1488. X  s->hs_clnum++;
  1489. X  s->hs_lavg = (100*s->hs_lsum) / s->hs_lnum; /* save 2 decimal points */
  1490. X  return(s->hs_lavg);
  1491. X}
  1492. X
  1493. X/* hash table operation: delete, insert, find */
  1494. Xcaddr_t
  1495. Xh_operation(what, ht, key, idx, idx2, d, b)
  1496. Xint what;
  1497. XHTABLE *ht;
  1498. Xcaddr_t key;
  1499. Xint idx;            /* preliminary index (-1 if none) */
  1500. Xint idx2;            /* secondary index (-1 if none) */
  1501. Xint *d;                /* return distance ? */
  1502. Xint *b;                /* return bucket # */
  1503. X{
  1504. X  int sidx, t;
  1505. X  int distance;
  1506. X  u_int cpkey;            /* compress version of key */
  1507. X  caddr_t *bp;            /* bucket pointer */
  1508. X  caddr_t *pbp = NULL;        /* previous bucket pointer for delete */
  1509. X  caddr_t data = NULL;
  1510. X
  1511. X  /* blather */
  1512. X  if (ht == NULL || HASH_OP_INVALID(what))
  1513. X    return(NULL);
  1514. X  if (idx < 0) {
  1515. X    if (ht->ht_cpfunc) {
  1516. X      cpkey = (*ht->ht_cpfunc)(key);
  1517. X      idx = (*ht->ht_hfunc)(ht->ht_M, ht->ht_logM, cpkey);
  1518. X    } else
  1519. X      idx = (*ht->ht_hfunc)(ht->ht_M, ht->ht_logM, key);
  1520. X  }
  1521. X  sidx = idx;
  1522. X  if (ht->ht_buckets == NULL) {
  1523. X    fprintf(stderr, "No buckets for hash table!  (Possibly using a freed \
  1524. X hash table handle)\n");
  1525. X    return(NULL);
  1526. X  }
  1527. X  bp = &ht->ht_buckets[idx];    /* start */
  1528. X  distance = 0;
  1529. X  if (b)
  1530. X    *b = sidx;
  1531. X
  1532. X  if (ht->ht_policy == HASH_POLICY_CHAIN) {
  1533. X    caddr_t hint, hint2;
  1534. X
  1535. X    /* distance should be updated */
  1536. X    data = (*ht->ht_chainops->hlo_find)(*bp,key,ht->ht_cfunc,
  1537. X                    &distance, &hint, &hint2);
  1538. X    switch (what) {
  1539. X    case HASH_OP_DELETE:
  1540. X      if (!data)
  1541. X    break;
  1542. X      /* key */
  1543. X      /* ignore error (should not happen!) */
  1544. X      (void)(*ht->ht_chainops->hlo_delete)(bp, key, &distance, hint, hint2);
  1545. X      update_hash_table_stats(&ht->ht_stats, -distance, -1);
  1546. X      break;
  1547. X    case HASH_OP_MEMBER:
  1548. X      if (data)
  1549. X    t = update_hash_lookup_stats(&ht->ht_stats, distance);
  1550. X      break;
  1551. X    case HASH_OP_INSERT:
  1552. X      if (data) {
  1553. X    t = update_hash_lookup_stats(&ht->ht_stats, distance);
  1554. X    break;
  1555. X      }
  1556. X      data= (*ht->ht_chainops->hlo_insert)(bp,key,ht->ht_afunc,
  1557. X                       &distance, hint,hint2);
  1558. X      update_hash_table_stats(&ht->ht_stats, distance, 1);
  1559. X      break;
  1560. X    }
  1561. X    if (d)
  1562. X      *d = distance;
  1563. X    return(data);
  1564. X  }
  1565. X
  1566. X  do {
  1567. X    if (*bp == NULL) {
  1568. X      switch (what) {
  1569. X      case HASH_OP_DELETE:        /* finished delete */
  1570. X    break;
  1571. X      case HASH_OP_MEMBER:
  1572. X    data = NULL;
  1573. X    break;
  1574. X      case HASH_OP_INSERT:
  1575. X    /* left with insert */
  1576. X    data = ht->ht_afunc ? (*ht->ht_afunc)(key) : key;
  1577. X    *bp = data;
  1578. X    update_hash_table_stats(&ht->ht_stats, distance, 1);
  1579. X    break;
  1580. X      }
  1581. X      if (d)
  1582. X    *d = distance;
  1583. X      return(data);
  1584. X    } else {
  1585. X      switch (what) {
  1586. X      case HASH_OP_DELETE:
  1587. X    /* if we haven't found an key to delete, try to find it */
  1588. X    if (!pbp) {
  1589. X      if ((*ht->ht_cfunc)(key, *bp) == 0) {
  1590. X        data = *bp;        /* save return key */
  1591. X        *bp = NULL;        /* clear out this bucket */
  1592. X        pbp = bp;        /* remember this bucket */
  1593. X        update_hash_table_stats(&ht->ht_stats, -distance, -1);
  1594. X      }
  1595. X    } else {
  1596. X      /* delete old distance */
  1597. X      update_hash_table_stats(&ht->ht_stats, -distance, -1);
  1598. X      /* insert new distance */
  1599. X      update_hash_table_stats(&ht->ht_stats, distance-1, 1);
  1600. X      *pbp = *bp;        /* move bucket */
  1601. X      *bp = NULL;        /* clear out this bucket */
  1602. X      pbp = bp;        /* remember this bucket */
  1603. X    }
  1604. X      default:
  1605. X    if ((*ht->ht_cfunc)(key, *bp) == 0) {
  1606. X      t = update_hash_lookup_stats(&ht->ht_stats, distance);
  1607. X      if (d)
  1608. X        *d = distance;
  1609. X      return(*bp);        /* done */
  1610. X    }
  1611. X      }
  1612. X    }
  1613. X    if (idx2 < 0 && ht->ht_hfunc2)
  1614. X      if (ht->ht_cpfunc) 
  1615. X    idx2 = (*ht->ht_hfunc2)(ht->ht_M, ht->ht_logM, idx, cpkey);
  1616. X      else
  1617. X    idx2 = (*ht->ht_hfunc2)(ht->ht_M, ht->ht_logM, idx, key);
  1618. X    distance++;
  1619. X    idx += idx2 > 0 ? idx2 : 1; /* bump index */
  1620. X    bp++;            /* advance bucket pointer */
  1621. X    if (idx >= ht->ht_M) {    /* need to wrap around */
  1622. X      idx %= ht->ht_M;        /* push index about */
  1623. X      bp = &ht->ht_buckets[idx]; /* and reset buckets */
  1624. X    }
  1625. X  } while (sidx != idx);
  1626. X  return(NULL);
  1627. X}
  1628. X
  1629. X/* return hash statistics */
  1630. Xstruct hash_statistics *
  1631. Xh_statistics(h)
  1632. XHTABLE *h;
  1633. X{
  1634. X  return(&h->ht_stats);
  1635. X}
  1636. X
  1637. X
  1638. X/* for linked list */
  1639. Xstruct hash_chain_item {
  1640. X  struct hash_chain_item *hci_next; /* pointer to next item in chain */
  1641. X  caddr_t hci_data;        /* pointer to data */
  1642. X};
  1643. X
  1644. X/*
  1645. X * hint == previous(hint2)
  1646. X *  hint2 is the match node or node whose data is > than current
  1647. X *
  1648. X*/
  1649. XPRIVATE caddr_t
  1650. Xlist_find(h, key, cmp, distance, hint, hint2)
  1651. Xstruct hash_chain_item *h;
  1652. Xcaddr_t key;
  1653. Xint (*cmp)();
  1654. Xint *distance;
  1655. Xstruct hash_chain_item **hint;
  1656. Xstruct hash_chain_item **hint2;
  1657. X{
  1658. X  struct hash_chain_item *hp = NULL;
  1659. X  int d,c;
  1660. X
  1661. X  *distance = 0;        /* no distnace */
  1662. X  *hint = NULL;            /* mark no hint */
  1663. X  *hint2 = NULL;
  1664. X  if (h == NULL)
  1665. X    return(NULL);
  1666. X  for (d = 0 ; h ; h = h->hci_next) {
  1667. X    if ((c = (*cmp)(key, h->hci_data)) >= 0)
  1668. X      break;
  1669. X    d++;
  1670. X    hp = h;
  1671. X  }
  1672. X  if (distance)
  1673. X    *distance = d;
  1674. X  if (hint2)
  1675. X    *hint2 = h;
  1676. X  if (hint)
  1677. X    *hint = hp;
  1678. X  return(c == 0 ? h->hci_data : NULL);
  1679. X}
  1680. X
  1681. X/*
  1682. X * insert item into chain.  hint is from the lookup and helps us insert
  1683. X * distance is from lookup too (we could choose to change)
  1684. X *
  1685. X * hint == previous(hint2)
  1686. X *  hint2 is the match node or node whose data is > than current
  1687. X * return 0 on success, -1 on failure.
  1688. X *
  1689. X */
  1690. X/*ARGSUSED*/
  1691. XPRIVATE caddr_t
  1692. Xlist_insert(head, key, alloc, distance, hint, hint2)
  1693. Xcaddr_t *head;
  1694. Xcaddr_t key;
  1695. Xcaddr_t (*alloc)();
  1696. Xint *distance;
  1697. Xstruct hash_chain_item *hint;
  1698. Xstruct hash_chain_item *hint2;
  1699. X{
  1700. X  struct hash_chain_item *h;
  1701. X
  1702. X  h = (struct hash_chain_item *)malloc(sizeof(struct hash_chain_item));
  1703. X  if (h == NULL)
  1704. X    return(NULL);
  1705. X  h->hci_data = alloc ? (*alloc)(key) : key;
  1706. X  h->hci_next = hint2;
  1707. X  if (hint)
  1708. X    hint->hci_next = h;
  1709. X  else
  1710. X    *head = (caddr_t)h;
  1711. X  return(h->hci_data);
  1712. X}
  1713. X
  1714. X/*
  1715. X * assumes a find has been done, hint is set by find and item exists
  1716. X *  in the list
  1717. X * head - head of list
  1718. X * item - data (unused)
  1719. X * hint - previous node to one that contains item
  1720. X * distance - distance to update (not done) (may be deleted)
  1721. X *
  1722. X*/
  1723. X/*ARGSUSED*/
  1724. XPRIVATE int
  1725. Xlist_delete(head, key, distance, hint, hint2)
  1726. Xcaddr_t *head;
  1727. Xcaddr_t key;
  1728. Xint *distance;            /* not used */
  1729. Xstruct hash_chain_item *hint;
  1730. Xstruct hash_chain_item *hint2;
  1731. X{
  1732. X  /* trust our input: two things could be wrong, first */
  1733. X  /* hint2 == NULL ==> nothing to delete */
  1734. X  /* hint2 != "key" ==> item not in list */
  1735. X  if (hint == NULL) {
  1736. X    *head = (caddr_t)hint2->hci_next;    /* remove */
  1737. X    free((caddr_t)hint2);
  1738. X    return(TRUE);
  1739. X  }
  1740. X  hint->hci_next = hint2->hci_next; /* unlink */
  1741. X  free((caddr_t)hint2);        /* get rid of node */
  1742. X  return(TRUE);
  1743. X}
  1744. X
  1745. X/* gets first item on list and returns data, freeing up node */
  1746. XPRIVATE caddr_t
  1747. Xlist_get(h)
  1748. Xstruct hash_chain_item **h;
  1749. X{
  1750. X  struct hash_chain_item *n;
  1751. X  caddr_t d;
  1752. X
  1753. X  if (h == NULL || *h == NULL)
  1754. X    return(NULL);
  1755. X  n = *h;            /* get item */
  1756. X  *h = n->hci_next;        /* and remove */
  1757. X  d = n->hci_data;
  1758. X  free((caddr_t)n);
  1759. X  return(d);
  1760. X}
  1761. X
  1762. X/* do hash division method */
  1763. X/*ARGSUSED*/
  1764. XPRIVATE u_int
  1765. Xhash_division(M, logM, idx)
  1766. Xint M;
  1767. Xint logM;
  1768. Xu_int idx;
  1769. X{
  1770. X  return(idx % M);
  1771. X}
  1772. X
  1773. X/* will work will with M if M-2,M are twin primes */
  1774. X/*ARGSUSED*/
  1775. XPRIVATE u_int
  1776. Xhash2_division(M, logM, hidx, idx)
  1777. Xint M;
  1778. Xint logM;
  1779. Xu_int hidx;
  1780. Xu_int idx;
  1781. X{
  1782. X  return(1 + (idx % (M-2)));
  1783. X}
  1784. X
  1785. X/* handle multiplicative method - hopefully the multiplier gives us */
  1786. X/* good range */
  1787. X/*ARGSUSED*/
  1788. XPRIVATE u_int
  1789. Xhash_multiplicative(M, logM, idx)
  1790. Xint M;
  1791. Xint logM;
  1792. Xu_int idx;
  1793. X{
  1794. X  return(((u_int)idx*A_MULTIPLIER>>(8*sizeof(int)-logM)));
  1795. X}
  1796. X
  1797. X/* the r more bits -- should be indepdent of the first r bits */
  1798. X/*ARGSUSED*/
  1799. XPRIVATE u_int
  1800. Xhash2_multiplicative(M, logM, hidx, idx)
  1801. Xint M;
  1802. Xint logM;
  1803. Xu_int hidx;
  1804. Xu_int idx;
  1805. X{
  1806. X  return(((u_int)idx*A_MULTIPLIER>>(8*sizeof(int)-logM-logM)|1) );
  1807. X}
  1808. X
  1809. X#ifdef TESTIT
  1810. X/* test program */
  1811. Xu_int
  1812. Xdocomp(data)
  1813. Xchar *data;
  1814. X{
  1815. X  u_int j;
  1816. X  j = 0;
  1817. X  while (*data)
  1818. X    j = ((j + *data++) >> 1) | j<<31;
  1819. X  return(j);
  1820. X}
  1821. X
  1822. Xchar *
  1823. Xalloc_func(p)
  1824. Xchar *p;
  1825. X{
  1826. X  char *d = (caddr_t)malloc(strlen(p) + 1);
  1827. X  strcpy(d, p);
  1828. X  return(d);
  1829. X}
  1830. X
  1831. Xdumpstats(msg, s)
  1832. Xchar *msg;
  1833. Xstruct hash_statistics *s;
  1834. X{
  1835. X  printf("%s\n\t %d bkts used, avg dist = %d.%02d, max dist = %d\n",
  1836. X     msg,
  1837. X     s->hs_used, s->hs_davg/100, s->hs_davg % 100,
  1838. X     s->hs_dmax);
  1839. X}
  1840. X
  1841. Xmain()
  1842. X{
  1843. X  HTABLE *hpc, *hplp, *hpdh;
  1844. X  extern strcmp();
  1845. X  char buf[BUFSIZ];
  1846. X  int b, d, op;
  1847. X  char *p;
  1848. X
  1849. X#define X 16 
  1850. X
  1851. X  hpc = (HTABLE *)h_new(HASH_POLICY_CHAIN, HASH_TYPE_DIVISION, X,
  1852. X            strcmp, alloc_func, docomp, NULL, NULL, NULL);
  1853. X  hplp = (HTABLE *)h_new(HASH_POLICY_LINEAR_PROBE,
  1854. X             HASH_TYPE_MULTIPLICATIVE, X, strcmp,
  1855. X             alloc_func, docomp, NULL, NULL, NULL);
  1856. X  hpdh = (HTABLE *)h_new(HASH_POLICY_DOUBLE_HASH,
  1857. X             HASH_TYPE_MULTIPLICATIVE, X, strcmp,
  1858. X             alloc_func, docomp, NULL, NULL, NULL);
  1859. X  while (gets(buf) != NULL) {
  1860. X    p = buf+1;
  1861. X    switch (buf[0]) {
  1862. X    case '+':
  1863. X      printf("INSERT %s\n", buf+1);
  1864. X      op = HASH_OP_INSERT;
  1865. X      break;
  1866. X    case '-':
  1867. X      printf("DELETE %s\n", buf+1);
  1868. X      op = HASH_OP_DELETE;
  1869. X      break;
  1870. X    case ' ':
  1871. X      printf("FIND %s\n", buf+1);
  1872. X      op = HASH_OP_MEMBER;
  1873. X      break;
  1874. X    default:
  1875. X      op = HASH_OP_INSERT;
  1876. X      p = buf;
  1877. X    }
  1878. X    if ((h_operation(op, hpc, p, -1, -1, &d, &b)))
  1879. X      printf("chain: %s at distance %d from bucket %d\n", p, d,b);
  1880. X    else
  1881. X      printf("chain hash table overflow or item not in table\n");
  1882. X    if ((h_operation(op, hplp, p, -1, -1, &d, &b)))
  1883. X      printf("linear probe: %s at distance %d from bucket %d\n", p, d,b);
  1884. X    else
  1885. X      printf("linear probe hash table overflow or item not in table\n");
  1886. X    if ((h_operation(op, hpdh, p, -1, -1, &d, &b)))
  1887. X      printf("double hash: %s at distance %d from bucket %d\n", p, d,b);
  1888. X    else
  1889. X      printf("double hash table overflow or item not in table\n");
  1890. X  }
  1891. X  dumpstats("double hash with multiplicative hash", h_statistics(hpdh));
  1892. X  h_redefine(hpdh, HASH_POLICY_CHAIN,HASH_TYPE_DIVISION, X, NULL,
  1893. X         NULL, NULL, NULL,NULL,NULL);
  1894. X  dumpstats("redefine above as chain with division hash", h_statistics(hpdh));
  1895. X  h_redefine(hpdh, HASH_POLICY_LINEAR_PROBE,HASH_TYPE_MULTIPLICATIVE,
  1896. X         X, NULL,NULL,NULL,NULL,NULL,NULL);
  1897. X  dumpstats("redefine above as linear probe with multiplicative hash",
  1898. X        h_statistics(hpdh));
  1899. X  dumpstats("chain with division hash", h_statistics(hpc));
  1900. X  dumpstats("linear probe with multiplicative hash", h_statistics(hplp));
  1901. X  h_free(hpdh, free);
  1902. X}
  1903. X#endif
  1904. END_OF_FILE
  1905.   if test 21202 -ne `wc -c <'hash.c'`; then
  1906.     echo shar: \"'hash.c'\" unpacked with wrong size!
  1907.   fi
  1908.   # end of 'hash.c'
  1909. fi
  1910. echo shar: End of archive 1 \(of 3\).
  1911. cp /dev/null ark1isdone
  1912. MISSING=""
  1913. for I in 1 2 3 ; do
  1914.     if test ! -f ark${I}isdone ; then
  1915.     MISSING="${MISSING} ${I}"
  1916.     fi
  1917. done
  1918. if test "${MISSING}" = "" ; then
  1919.     echo You have unpacked all 3 archives.
  1920.     rm -f ark[1-9]isdone
  1921. else
  1922.     echo You still must unpack the following archives:
  1923.     echo "        " ${MISSING}
  1924. fi
  1925. exit 0
  1926. exit 0 # Just in case...
  1927.