2 * Copyright 1993, 1995 Christopher Seiwald.
4 * This file is part of Jam - see jam.c for Copyright information.
8 * hash.c - simple in-memory hashing routines
12 * hashinit() - initialize a hash table, returning a handle
13 * hashitem() - find a record in the table, and optionally enter a new one
14 * hashdone() - free a hash table, given its handle
18 * hashrehash() - resize and rebuild hp->tab, the hash table
20 * 4/29/93 - ensure ITEM's are aligned
21 * 11/04/02 (seiwald) - const-ing for string literals
22 * 01/31/02 (seiwald) - keyval now unsigned (cray-ziness)
28 /* header attached to all data items entered into a hash table. */
31 unsigned int keyval
; /* for quick comparisons */
35 /* this structure overlays the one handed to hashenter() */
36 /* it's actual size is given to hashinit() */
39 /* rest of user data */
49 #define MAX_LISTS (32)
51 /* the hash table, just an array of item pointers */
56 int bloat
; /* tab.nel / items.nel */
57 int inel
; /* initial number of elements */
58 /* the array of records, maintained by these routines essentially a microallocator */
60 int more
; /* how many more ITEMs fit in lists[ list ] */
61 char *next
; /* where to put more ITEMs in lists[ list ] */
62 int datalen
; /* length of records in this hash table */
63 int size
; /* sizeof(ITEM) + aligned datalen */
64 int nel
; /* total ITEMs held by all lists[] */
65 int list
; /* index into lists[] */
67 int nel
; /* total ITEMs held by this list */
68 char *base
; /* base of ITEMs array */
71 const char *name
; /* just for hashstats() */
75 static void hashrehash (struct hash
*hp
);
76 static void hashstat (struct hash
*hp
);
80 * hashitem() - find a record in the table, and optionally enter a new one
82 int hashitem (struct hash
*hp
, HASHDATA
**data
, int enter
) {
85 unsigned char *b
= (unsigned char *)(*data
)->key
;
88 if (enter
&& !hp
->items
.more
) hashrehash(hp
);
89 if (!enter
&& !hp
->items
.nel
) return 0;
91 while (*b
) keyval
= keyval
*2147059363 + *b
++;
92 base
= hp
->tab
.base
+(keyval
%hp
->tab
.nel
);
93 for (i
= *base
; i
; i
= i
->hdr
.next
) {
94 if (keyval
== i
->hdr
.keyval
&& !strcmp(i
->data
.key
, (*data
)->key
)) {
100 i
= (ITEM
*)hp
->items
.next
;
101 hp
->items
.next
+= hp
->items
.size
;
103 memcpy((char *)&i
->data
, (char *)*data
, hp
->items
.datalen
);
104 i
->hdr
.keyval
= keyval
;
114 * hashrehash() - resize and rebuild hp->tab, the hash table
116 static void hashrehash (struct hash
*hp
) {
117 int i
= ++hp
->items
.list
;
119 hp
->items
.more
= i
? 2 * hp
->items
.nel
: hp
->inel
;
120 hp
->items
.next
= (char *)malloc(hp
->items
.more
* hp
->items
.size
);
122 hp
->items
.lists
[i
].nel
= hp
->items
.more
;
123 hp
->items
.lists
[i
].base
= hp
->items
.next
;
124 hp
->items
.nel
+= hp
->items
.more
;
126 if (hp
->tab
.base
) free((char *)hp
->tab
.base
);
128 hp
->tab
.nel
= hp
->items
.nel
* hp
->bloat
;
129 hp
->tab
.base
= (ITEM
**)malloc(hp
->tab
.nel
* sizeof(ITEM
**));
131 memset((char *)hp
->tab
.base
, '\0', hp
->tab
.nel
* sizeof(ITEM
*));
133 for (i
= 0; i
< hp
->items
.list
; ++i
) {
134 int nel
= hp
->items
.lists
[i
].nel
;
135 char *next
= hp
->items
.lists
[i
].base
;
137 for (; nel
--; next
+= hp
->items
.size
) {
138 ITEM
*i
= (ITEM
*)next
;
139 ITEM
**ip
= hp
->tab
.base
+i
->hdr
.keyval
%hp
->tab
.nel
;
148 #define ALIGNED(x) ((x+sizeof(ITEM)-1)&(~(sizeof(ITEM)-1)))
152 * hashinit() - initialize a hash table, returning a handle
154 struct hash
*hashinit (int datalen
, const char *name
) {
155 struct hash
*hp
= (struct hash
*)malloc(sizeof(*hp
));
159 hp
->tab
.base
= (ITEM
**)0;
161 hp
->items
.datalen
= datalen
;
162 hp
->items
.size
= sizeof(struct hashhdr
)+ALIGNED(datalen
);
172 * hashdone() - free a hash table, given its handle
174 void hashdone (struct hash
*hp
) {
178 if (DEBUG_MEM
) hashstat(hp
);
179 if (hp
->tab
.base
) free((char *)hp
->tab
.base
);
180 for (i
= 0; i
<= hp
->items
.list
; i
++) free(hp
->items
.lists
[i
].base
);
187 static void hashstat (struct hash
*hp
) {
188 ITEM
**tab
= hp
->tab
.base
;
189 int nel
= hp
->tab
.nel
;
192 int run
= (tab
[nel
-1] != (ITEM
*)0);
195 for (i
= nel
; i
> 0; --i
) {
196 if ((here
= (*tab
++ != (ITEM
*)0))) ++count
;
197 if (here
&& !run
) ++sets
;
200 printf("%s table: %d+%d+%d (%dK+%dK) items+table+hash, %f density\n",
205 hp
->items
.nel
*hp
->items
.size
/1024,
206 (int)(hp
->tab
.nel
*sizeof(ITEM
**)/1024),
207 (float)count
/(float)sets