1 /* $RCSfile: hash.c,v $$Revision: 4.0.1.2 $$Date: 91/11/05 17:24:13 $
3 * Copyright (c) 1991, Larry Wall
5 * You may distribute under the terms of either the GNU General Public
6 * License or the Artistic License, as specified in the README file.
9 * Revision 4.0.1.2 91/11/05 17:24:13 lwall
10 * patch11: saberized perl
12 * Revision 4.0.1.1 91/06/07 11:10:11 lwall
13 * patch4: new copyright notice
15 * Revision 4.0 91/03/20 01:22:26 lwall
23 static char coeff[] = {
24 61,59,53,47,43,41,37,31,29,23,17,13,11,7,3,1,
25 61,59,53,47,43,41,37,31,29,23,17,13,11,7,3,1,
26 61,59,53,47,43,41,37,31,29,23,17,13,11,7,3,1,
27 61,59,53,47,43,41,37,31,29,23,17,13,11,7,3,1,
28 61,59,53,47,43,41,37,31,29,23,17,13,11,7,3,1,
29 61,59,53,47,43,41,37,31,29,23,17,13,11,7,3,1,
30 61,59,53,47,43,41,37,31,29,23,17,13,11,7,3,1,
31 61,59,53,47,43,41,37,31,29,23,17,13,11,7,3,1};
33 static void hfreeentries();
36 hfetch(tb,key,klen,lval)
56 Newz(503,tb->tbl_array, tb->tbl_max + 1, HENT*);
61 /* The hash function we use on symbols has to be equal to the first
62 * character when taken modulo 128, so that str_reset() can be implemented
63 * efficiently. We throw in the second character and the last character
64 * (times 128) so that long chains of identifiers starting with the
65 * same letter don't have to be strEQ'ed within hfetch(), since it
66 * compares hash values before trying strEQ().
68 if (!tb->tbl_coeffsize)
69 hash = *key + 128 * key[1] + 128 * key[klen-1]; /* assuming klen > 0 */
70 else { /* use normal coefficients */
71 if (klen < tb->tbl_coeffsize)
74 maxi = tb->tbl_coeffsize;
75 for (s=key, i=0, hash = 0;
76 i < maxi; /*SUPPRESS 8*/
77 s++, i++, hash *= 5) {
78 hash += *s * coeff[i];
82 entry = tb->tbl_array[hash & tb->tbl_max];
83 for (; entry; entry = entry->hent_next) {
84 if (entry->hent_hash != hash) /* strings can't be equal */
86 if (entry->hent_klen != klen)
88 if (bcmp(entry->hent_key,key,klen)) /* is this it? */
90 return entry->hent_val;
97 dcontent = gdbm_fetch(tb->tbl_dbm,dkey);
99 dcontent = dbm_fetch(tb->tbl_dbm,dkey);
101 if (dcontent.dptr) { /* found one */
102 str = Str_new(60,dcontent.dsize);
103 str_nset(str,dcontent.dptr,dcontent.dsize);
104 hstore(tb,key,klen,str,hash); /* cache it */
109 if (lval) { /* gonna assign to this, so it better be there */
111 hstore(tb,key,klen,str,hash);
118 hstore(tb,key,klen,val,hash)
127 register HENT *entry;
128 register HENT **oentry;
137 else if (!tb->tbl_coeffsize)
138 hash = *key + 128 * key[1] + 128 * key[klen-1];
139 else { /* use normal coefficients */
140 if (klen < tb->tbl_coeffsize)
143 maxi = tb->tbl_coeffsize;
144 for (s=key, i=0, hash = 0;
145 i < maxi; /*SUPPRESS 8*/
146 s++, i++, hash *= 5) {
147 hash += *s * coeff[i];
152 Newz(505,tb->tbl_array, tb->tbl_max + 1, HENT*);
154 oentry = &(tb->tbl_array[hash & tb->tbl_max]);
157 for (entry = *oentry; entry; i=0, entry = entry->hent_next) {
158 if (entry->hent_hash != hash) /* strings can't be equal */
160 if (entry->hent_klen != klen)
162 if (bcmp(entry->hent_key,key,klen)) /* is this it? */
164 Safefree(entry->hent_val);
165 entry->hent_val = val;
168 New(501,entry, 1, HENT);
170 entry->hent_klen = klen;
171 entry->hent_key = nsavestr(key,klen);
172 entry->hent_val = val;
173 entry->hent_hash = hash;
174 entry->hent_next = *oentry;
177 /* hdbmstore not necessary here because it's called from stabset() */
179 if (i) { /* initial entry? */
182 if (tb->tbl_dbm && tb->tbl_max >= DBM_CACHE_MAX)
185 if (tb->tbl_fill > tb->tbl_dosplit)
189 else if (tb->tbl_dbm) { /* is this just a cache for dbm file? */
190 void hentdelayfree();
192 entry = tb->tbl_array[hash & tb->tbl_max];
193 oentry = &entry->hent_next;
195 while (entry) { /* trim chain down to 1 entry */
196 *oentry = entry->hent_next;
197 hentdelayfree(entry); /* no doubt they'll want this next. */
215 register HENT *entry;
216 register HENT **oentry;
223 if (!tb || !tb->tbl_array)
225 if (!tb->tbl_coeffsize)
226 hash = *key + 128 * key[1] + 128 * key[klen-1];
227 else { /* use normal coefficients */
228 if (klen < tb->tbl_coeffsize)
231 maxi = tb->tbl_coeffsize;
232 for (s=key, i=0, hash = 0;
233 i < maxi; /*SUPPRESS 8*/
234 s++, i++, hash *= 5) {
235 hash += *s * coeff[i];
239 oentry = &(tb->tbl_array[hash & tb->tbl_max]);
242 for (; entry; i=0, oentry = &entry->hent_next, entry = *oentry) {
243 if (entry->hent_hash != hash) /* strings can't be equal */
245 if (entry->hent_klen != klen)
247 if (bcmp(entry->hent_key,key,klen)) /* is this it? */
249 *oentry = entry->hent_next;
250 str = str_mortal(entry->hent_val);
260 gdbm_delete(tb->tbl_dbm,dkey);
262 dbm_delete(tb->tbl_dbm,dkey);
279 int oldsize = tb->tbl_max + 1;
280 register int newsize = oldsize * 2;
284 register HENT *entry;
285 register HENT **oentry;
288 Renew(a, newsize, HENT*);
289 Zero(&a[oldsize], oldsize, HENT*); /* zero 2nd half*/
290 tb->tbl_max = --newsize;
291 tb->tbl_dosplit = tb->tbl_max * FILLPCT / 100;
294 for (i=0; i<oldsize; i++,a++) {
295 if (!*a) /* non-existent */
298 for (oentry = a, entry = *a; entry; entry = *oentry) {
299 if ((entry->hent_hash & newsize) != i) {
300 *oentry = entry->hent_next;
301 entry->hent_next = *b;
308 oentry = &entry->hent_next;
310 if (!*a) /* everything moved */
321 Newz(502,tb, 1, HASH);
323 tb->tbl_coeffsize = lookat;
324 tb->tbl_max = 7; /* it's a normal associative array */
325 tb->tbl_dosplit = tb->tbl_max * FILLPCT / 100;
328 tb->tbl_max = 127; /* it's a symbol table */
329 tb->tbl_dosplit = 128; /* so never split */
335 (void)hiterinit(tb); /* so each() will start off right */
345 str_free(hent->hent_val);
346 Safefree(hent->hent_key);
356 str_2mortal(hent->hent_val); /* free between statements */
357 Safefree(hent->hent_key);
368 hfreeentries(tb,dodbm);
372 (void)bzero((char*)tb->tbl_array, (tb->tbl_max + 1) * sizeof(HENT*));
377 hfreeentries(tb,dodbm)
382 register HENT *ohent = Null(HENT*);
397 if (!tb || !tb->tbl_array)
400 if ((old_dbm = tb->tbl_dbm) && dodbm) {
402 while (dkey = gdbm_firstkey(tb->tbl_dbm), dkey.dptr) {
404 while (dkey = dbm_firstkey(tb->tbl_dbm), dkey.dptr) {
408 nextdkey = gdbm_nextkey(tb->tbl_dbm, dkey);
412 nextdkey = dbm_nextkey(tb->tbl_dbm, dkey);
414 nextdkey = dbm_nextkey(tb->tbl_dbm);
417 nextdkey = nextkey(dkey);
421 gdbm_delete(tb->tbl_dbm,dkey);
423 dbm_delete(tb->tbl_dbm,dkey);
426 } while (dkey.dptr); /* one way or another, this works */
429 tb->tbl_dbm = 0; /* now clear just cache */
433 while (hent = hiternext(tb)) { /* concise but not very efficient */
439 tb->tbl_dbm = old_dbm;
450 hfreeentries(tb,dodbm);
451 Safefree(tb->tbl_array);
460 tb->tbl_eiter = Null(HENT*);
468 register HENT *entry;
473 entry = tb->tbl_eiter;
478 key.dptr = entry->hent_key;
479 key.dsize = entry->hent_klen;
480 key = gdbm_nextkey(tb->tbl_dbm, key);
484 key.dptr = entry->hent_key;
485 key.dsize = entry->hent_klen;
486 key = dbm_nextkey(tb->tbl_dbm, key);
488 key = dbm_nextkey(tb->tbl_dbm);
491 key.dptr = entry->hent_key;
492 key.dsize = entry->hent_klen;
498 Newz(504,entry, 1, HENT);
499 tb->tbl_eiter = entry;
501 key = gdbm_firstkey(tb->tbl_dbm);
503 key = dbm_firstkey(tb->tbl_dbm);
506 entry->hent_key = key.dptr;
507 entry->hent_klen = key.dsize;
510 str_free(entry->hent_val);
512 tb->tbl_eiter = Null(HENT*);
519 Newz(506,tb->tbl_array, tb->tbl_max + 1, HENT*);
522 entry = entry->hent_next;
525 if (tb->tbl_riter > tb->tbl_max) {
529 entry = tb->tbl_array[tb->tbl_riter];
533 tb->tbl_eiter = entry;
538 hiterkey(entry,retlen)
539 register HENT *entry;
542 *retlen = entry->hent_klen;
543 return entry->hent_key;
549 register HENT *entry;
555 key.dptr = entry->hent_key;
556 key.dsize = entry->hent_klen;
558 content = gdbm_fetch(tb->tbl_dbm,key);
560 content = dbm_fetch(tb->tbl_dbm,key);
562 if (!entry->hent_val)
563 entry->hent_val = Str_new(62,0);
564 str_nset(entry->hent_val,content.dptr,content.dsize);
567 return entry->hent_val;
577 # include <sys/file.h>
588 #define O_CREAT 01000
592 static int dbmrefcnt = 0;
596 hdbmopen(tb,fname,mode)
604 if (tb->tbl_dbm) /* never really closed it */
611 hclear(tb, FALSE); /* clear cache */
614 tb->tbl_dbm = gdbm_open(fname, 0, GDBM_WRCREAT,mode, (void *) NULL);
616 tb->tbl_dbm = gdbm_open(fname, 0, GDBM_WRITER, mode, (void *) NULL);
618 tb->tbl_dbm = gdbm_open(fname, 0, GDBM_READER, mode, (void *) NULL);
622 tb->tbl_dbm = dbm_open(fname, O_RDWR|O_CREAT, mode);
624 tb->tbl_dbm = dbm_open(fname, O_RDWR, mode);
626 tb->tbl_dbm = dbm_open(fname, O_RDONLY, mode);
629 fatal("Old dbm can only open one database");
630 sprintf(buf,"%s.dir",fname);
631 if (stat(buf, &statbuf) < 0) {
632 if (mode < 0 || close(creat(buf,mode)) < 0)
634 sprintf(buf,"%s.pag",fname);
635 if (close(creat(buf,mode)) < 0)
638 tb->tbl_dbm = dbminit(fname) >= 0;
641 if (!tb->tbl_array && tb->tbl_dbm != 0)
642 Newz(507,tb->tbl_array, tb->tbl_max + 1, HENT*);
643 return tb->tbl_dbm != 0;
650 if (tb && tb->tbl_dbm) {
652 gdbm_close(tb->tbl_dbm);
656 dbm_close(tb->tbl_dbm);
659 /* dbmrefcnt--; */ /* doesn't work, rats */
664 warn("Close on unopened dbm file");
668 hdbmstore(tb,key,klen,str)
674 datum dkey, dcontent;
677 if (!tb || !tb->tbl_dbm)
681 dcontent.dptr = str_get(str);
682 dcontent.dsize = str->str_cur;
684 error = gdbm_store(tb->tbl_dbm, dkey, dcontent, GDBM_REPLACE);
686 error = dbm_store(tb->tbl_dbm, dkey, dcontent, DBM_REPLACE);
690 fatal("No write permission to dbm file");
691 warn("dbm store returned %d, errno %d, key \"%s\"",error,errno,key);
693 dbm_clearerr(tb->tbl_dbm);
698 #endif /* SOME_DBM */