1#include <signal.h>2#include <stdlib.h>3#include <stdio.h>4#include <string.h>5#include <limits.h>67#ifndef SIGHUP8#define SIGHUP 09#endif1011extern unsigned genhash(char *);1213static sig_atomic_t signalled;14static unsigned long M, K, S;1516static unsigned17hash(char *s)18{19 unsigned h;2021 h = genhash(s);2223 return (unsigned short) h;24}2526static int27foundmap(unsigned *th, int ntok)28{29 int i;30 unsigned h;31 char bmap[USHRT_MAX];3233 for (K = 1; (unsigned short) (K+1) != 0; K += 2) {34 if (signalled) {35 signalled = 0;36 fprintf(stderr, "M=%lu,K=%lu,S=%lu\n", M, K, S);37 }38 memset(bmap, 0, sizeof(bmap));3940 for (i = 0; i < ntok; i++) {41 h = (th[i]*K >> S) & M;42 if (bmap[h])43 break;44 bmap[h] = 1;45 }4647 if (i == ntok)48 return 1;49 }5051 return 0;52}5354static void55phash(char *toks[], int ntok)56{57 int i, j, nbits;58 unsigned *th, h;5960 if ((th = calloc(ntok, sizeof(*th))) == NULL) {61 perror("hash");62 exit(EXIT_FAILURE);63 }6465 for (i = 0; i < ntok; i++) {66 h = hash(toks[i]);67 for (j = 0; j < i && th[j] != h; j++)68 ;6970 if (i != j) {71 fprintf(stderr,72 "hash: collision %s-%s\n",73 toks[i],74 toks[j]);75 exit(EXIT_FAILURE);76 }77 th[i] = h;78 }7980 for (nbits = 1; 1<<nbits < ntok; ++nbits)81 ;8283 for (i = nbits+1; i < 16; i++) {84 M = ~((unsigned) -1 << i);8586 for (j = nbits; j < 32; j++) {87 S = 32 - j;8889 if (foundmap(th, ntok))90 goto found;91 }92 }9394 fputs("hash: not possible perfect hash\n", stderr);95 exit(EXIT_FAILURE);9697found:98 printf("unsigned long K=%lu, M=%lu, S=%lu;\n", K, M, S);99100 printf("short hashmap[%d] = {\n", 1<<i);101 for (i = 0; i < ntok; i++)102 printf("\t[%ld] = %d,\n", (th[i]*K >> S) & M, i+1);103 puts("};");104}105106static void107sighandler(int num)108{109 signalled = 1;110 signal(SIGHUP, sighandler);111}112113int114main()115{116 int nr, n;117 char line[BUFSIZ], **tokens, *tok;118119 nr = 0;120 tokens = NULL;121 for (;;) {122 if (!fgets(line, sizeof(line), stdin))123 break;124 n = strlen(line);125 if (n == 0)126 continue;127 if (line[n-1] != '\n') {128 fputs("error: line truncated\n", stderr);129 exit(EXIT_FAILURE);130 }131 line[n-1] = '\0';132133 tok = malloc(n);134 tokens = realloc(tokens, (nr+1) * sizeof(*tokens));135 if (!tokens || !tok) {136 perror("hash");137 exit(EXIT_FAILURE);138 }139 tokens[nr++] = memcpy(tok, line, n);140 }141142 if (ferror(stdin)) {143 perror("hash");144 exit(EXIT_FAILURE);145 }146147 signal(SIGHUP, sighandler);148149 if (nr != 0)150 phash(tokens, nr);151152 return 0;153}