1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220
|
/* hashrout.h -- Rubine's hash table package */
/* Copyright 1989 Carnegie Mellon University */
/* ChangeLog:
* 2-jan-85 rbd Added option to count entries: define COUNTER and
* HASHENTER routine will increment it on new entries
* 28-Apr-03 DM Explicit declaration of int type for HASHENTER()
*/
/*
* Generic symbol table functions
*
* After writing this code over for a bunch of interpreters
* I think I know how to do it once and for all, generally
* enough for most application.
* There are enough settable parameters to suit anyone, and
* the defaults usually do something sane.
*
* The basic idea is that you have a bunch of symbol table entries
* that need to be entered or looked up given a character string.
* Symbol table entries are usually structures, and one element
* of the structure must be the character string of the key.
* The structure should be given a type name, and these routines
* are informed of the type name via
* #define HASHTYPE type-name-of-symbol-table-entry
* You must inform the routines how to access the character string
* given the symbol table entry; for example
* #define HASHELEM(p) ((p).name)
* There are two size parameters - the number of different hash
* values and the number of symbol table entries to allocate at one
* time. Both default to 256.
* #define HASHVAL 128
* #define HASHENTRIES 512
* The name of the function that performs both entry and lookup is
* enter(name) - it takes one argument, a character string. The name
* of the function may be changed via
* #define HASHENTER new-name-for-enter-routine
* Note that if there is no entry in the table for name, name is entered
* automatically. The returned structure will have only the name
* field filled in; the rest of the fields are guarenteed to be zero
* so an application can check if this is the first time name was entered.
* If HASHPOINT is defined, the enter routine returns a pointer to a hash
* table entry. In the default case, i.e. HASHPOINT undefined, the
* enter routine returns an integer between zero and HASHENTRIES.
* The macro HASHENTRY(i) will, given that integer, return the
* table element (not a pointer to it), so for example,
* HASHENTRY(enter(x)).name == x.
* Any file that wishes to use HASHENTRY should have at the top
* #define HASHTYPE type-name-of-symbol-table-entry
* #include "hash.h"
* Note in this case at most HASHENTRIES entries will be allocated
* before hash table overflow. If HASHPOINT is defined, allocations
* will take place until memory runs out.
* By default, hash strings are copied into space obtained from malloc
* before being placed in new entry. This copying can be supressed
* by defining HASHNOCOPY.
* The following is an example of using the hash table stuff.
typedef struct {
char *n_name;
int n_value;
} symbolentry;
#define HASHTYPE symbolentry
#define HASHELEM(p) ((p).n_name)
#define HASHENTRIES 1024
#include "hashrout.h"
*/
/*
* OK, now the meat.
*/
#ifndef HASHTYPE
# include "-- HASHTYPE undefined"
#endif
#ifndef HASHELEM
# include "-- HASHELEM undefined"
#endif
#ifndef HASHVAL
# define HASHVAL 256
#endif
#ifndef HASHENTRIES
# define HASHENTRIES 256
#endif
#ifndef HASHENTER
# define HASHENTER enter
#endif
/*
* HASHNOCOPY, HASHPOINT are undefined by default
*/
/*
* get definition of hash elem structure
*/
#ifndef HASHENTRY
# include "hash.h"
#endif
/*
* Table of pointers, indexed by hash values
*/
hashelem *hashtab[HASHVAL];
/*
* First chunk of elements, pointer to the start,
* and index for allocation
*/
hashelem hashfirstchunk[HASHENTRIES];
hashelem *hashchunk = hashfirstchunk;
int hashindex = 0;
/*
* stdio.h if we don't have it yet
*/
#ifndef _NFILE
# include <stdio.h>
#endif
/*
* Declare counter if necessary
*/
#ifdef COUNTER
extern COUNTER;
#endif
/*
* The enter routine
*/
#ifdef HASHPOINT
HASHTYPE *
#else
int
#endif
HASHENTER (s)
char *s;
{
register int i, hash;
register hashelem *elem;
/*
* Compute s's hash value
* I really should look up some good hash functions, but
* I haven't bothered.
*/
for(i = 0, hash = 0; s[i] != '\0' && i < 15; i++)
hash += (i + 1) * s[i];
hash %= HASHVAL;
/*
* search for s in the table
*/
for(elem = hashtab[hash]; elem != NULL; elem = elem->h_next)
if(strcmp(s, HASHELEM((elem->h_elem))) == 0) { /* found it */
#ifdef HASHPOINT
return(&elem->h_elem);
#else
return(elem - hashfirstchunk);
#endif
}
if(hashindex >= HASHENTRIES) {
#ifdef HASHPOINT
char *calloc();
hashindex = 0;
hashchunk = (hashelem *) calloc(HASHENTRIES, sizeof(hashelem));
if(hashchunk == NULL) {
gprintf(FATAL, "No mem for hash symbol table\n");
EXIT(1);
#ifdef COUNTER
COUNTER++; /* optional symbol counter */
#endif
}
#else
gprintf(FATAL, "No hash table space, increase HASHENTRIES\n");
EXIT(1);
#endif
}
/*
* Splice a new entry into the list and fill in the string field
*/
elem = &hashchunk[hashindex++];
elem->h_next = hashtab[hash];
hashtab[hash] = elem;
#ifdef HASHNOCOPY
HASHELEM((elem->h_elem)) = s;
#else
{
char *strcpy();
HASHELEM((elem->h_elem)) = memget((strlen(s) + 1));
strcpy(HASHELEM((elem->h_elem)), s);
}
#endif
#ifdef HASHPOINT
return(&elem->h_elem);
#else
return(elem - hashfirstchunk);
#endif
}
|