1 /* $Header: hash.c,v 3.0.1.7 90/10/20 02:10:00 lwall Locked $
3 * Copyright (c) 1989, Larry Wall
5 * You may distribute under the terms of the GNU General Public License
6 * as specified in the README file that comes with the perl 3.0 kit.
9 * Revision 3.0.1.7 90/10/20 02:10:00 lwall
10 * patch37: hash.c called ndbm function on dbm system
12 * Revision 3.0.1.6 90/10/15 17:32:52 lwall
13 * patch29: non-existent array values no longer cause core dumps
14 * patch29: %foo = () will now clear dbm files
15 * patch29: dbm files couldn't be opened read only
16 * patch29: the cache array for dbm files wasn't correctly created on fetches
18 * Revision 3.0.1.5 90/08/13 22:18:27 lwall
19 * patch28: defined(@array) and defined(%array) didn't work right
21 * Revision 3.0.1.4 90/08/09 03:50:22 lwall
22 * patch19: dbmopen(name, 'filename', undef) now refrains from creating
24 * Revision 3.0.1.3 90/03/27 15:59:09 lwall
25 * patch16: @dbmvalues{'foo','bar'} could use the same cache entry for both values
27 * Revision 3.0.1.2 89/12/21 20:03:39 lwall
28 * patch7: errno may now be a macro with an lvalue
30 * Revision 3.0.1.1 89/11/11 04:34:18 lwall
31 * patch2: CX/UX needed to set the key each time in associative iterators
33 * Revision 3.0 89/10/18 15:18:32 lwall
41 static char coeff[] = {
42 61,59,53,47,43,41,37,31,29,23,17,13,11,7,3,1,
43 61,59,53,47,43,41,37,31,29,23,17,13,11,7,3,1,
44 61,59,53,47,43,41,37,31,29,23,17,13,11,7,3,1,
45 61,59,53,47,43,41,37,31,29,23,17,13,11,7,3,1,
46 61,59,53,47,43,41,37,31,29,23,17,13,11,7,3,1,
47 61,59,53,47,43,41,37,31,29,23,17,13,11,7,3,1,
48 61,59,53,47,43,41,37,31,29,23,17,13,11,7,3,1,
49 61,59,53,47,43,41,37,31,29,23,17,13,11,7,3,1};
51 static void hfreeentries();
54 hfetch(tb,key,klen,lval)
74 Newz(503,tb->tbl_array, tb->tbl_max + 1, HENT*);
79 /* The hash function we use on symbols has to be equal to the first
80 * character when taken modulo 128, so that str_reset() can be implemented
81 * efficiently. We throw in the second character and the last character
82 * (times 128) so that long chains of identifiers starting with the
83 * same letter don't have to be strEQ'ed within hfetch(), since it
84 * compares hash values before trying strEQ().
86 if (!tb->tbl_coeffsize)
87 hash = *key + 128 * key[1] + 128 * key[klen-1]; /* assuming klen > 0 */
88 else { /* use normal coefficients */
89 if (klen < tb->tbl_coeffsize)
92 maxi = tb->tbl_coeffsize;
93 for (s=key, i=0, hash = 0;
95 s++, i++, hash *= 5) {
96 hash += *s * coeff[i];
100 entry = tb->tbl_array[hash & tb->tbl_max];
101 for (; entry; entry = entry->hent_next) {
102 if (entry->hent_hash != hash) /* strings can't be equal */
104 if (entry->hent_klen != klen)
106 if (bcmp(entry->hent_key,key,klen)) /* is this it? */
108 return entry->hent_val;
114 dcontent = dbm_fetch(tb->tbl_dbm,dkey);
115 if (dcontent.dptr) { /* found one */
116 str = Str_new(60,dcontent.dsize);
117 str_nset(str,dcontent.dptr,dcontent.dsize);
118 hstore(tb,key,klen,str,hash); /* cache it */
123 if (lval) { /* gonna assign to this, so it better be there */
125 hstore(tb,key,klen,str,hash);
132 hstore(tb,key,klen,val,hash)
141 register HENT *entry;
142 register HENT **oentry;
150 else if (!tb->tbl_coeffsize)
151 hash = *key + 128 * key[1] + 128 * key[klen-1];
152 else { /* use normal coefficients */
153 if (klen < tb->tbl_coeffsize)
156 maxi = tb->tbl_coeffsize;
157 for (s=key, i=0, hash = 0;
159 s++, i++, hash *= 5) {
160 hash += *s * coeff[i];
165 Newz(505,tb->tbl_array, tb->tbl_max + 1, HENT*);
167 oentry = &(tb->tbl_array[hash & tb->tbl_max]);
170 for (entry = *oentry; entry; i=0, entry = entry->hent_next) {
171 if (entry->hent_hash != hash) /* strings can't be equal */
173 if (entry->hent_klen != klen)
175 if (bcmp(entry->hent_key,key,klen)) /* is this it? */
177 Safefree(entry->hent_val);
178 entry->hent_val = val;
181 New(501,entry, 1, HENT);
183 entry->hent_klen = klen;
184 entry->hent_key = nsavestr(key,klen);
185 entry->hent_val = val;
186 entry->hent_hash = hash;
187 entry->hent_next = *oentry;
190 /* hdbmstore not necessary here because it's called from stabset() */
192 if (i) { /* initial entry? */
195 if (tb->tbl_dbm && tb->tbl_max >= DBM_CACHE_MAX)
198 if (tb->tbl_fill > tb->tbl_dosplit)
202 else if (tb->tbl_dbm) { /* is this just a cache for dbm file? */
203 void hentdelayfree();
205 entry = tb->tbl_array[hash & tb->tbl_max];
206 oentry = &entry->hent_next;
208 while (entry) { /* trim chain down to 1 entry */
209 *oentry = entry->hent_next;
210 hentdelayfree(entry); /* no doubt they'll want this next. */
228 register HENT *entry;
229 register HENT **oentry;
236 if (!tb || !tb->tbl_array)
238 if (!tb->tbl_coeffsize)
239 hash = *key + 128 * key[1] + 128 * key[klen-1];
240 else { /* use normal coefficients */
241 if (klen < tb->tbl_coeffsize)
244 maxi = tb->tbl_coeffsize;
245 for (s=key, i=0, hash = 0;
247 s++, i++, hash *= 5) {
248 hash += *s * coeff[i];
252 oentry = &(tb->tbl_array[hash & tb->tbl_max]);
255 for (; entry; i=0, oentry = &entry->hent_next, entry = *oentry) {
256 if (entry->hent_hash != hash) /* strings can't be equal */
258 if (entry->hent_klen != klen)
260 if (bcmp(entry->hent_key,key,klen)) /* is this it? */
262 *oentry = entry->hent_next;
263 str = str_static(entry->hent_val);
272 dbm_delete(tb->tbl_dbm,dkey);
288 int oldsize = tb->tbl_max + 1;
289 register int newsize = oldsize * 2;
293 register HENT *entry;
294 register HENT **oentry;
297 Renew(a, newsize, HENT*);
298 Zero(&a[oldsize], oldsize, HENT*); /* zero 2nd half*/
299 tb->tbl_max = --newsize;
300 tb->tbl_dosplit = tb->tbl_max * FILLPCT / 100;
303 for (i=0; i<oldsize; i++,a++) {
304 if (!*a) /* non-existent */
307 for (oentry = a, entry = *a; entry; entry = *oentry) {
308 if ((entry->hent_hash & newsize) != i) {
309 *oentry = entry->hent_next;
310 entry->hent_next = *b;
317 oentry = &entry->hent_next;
319 if (!*a) /* everything moved */
330 Newz(502,tb, 1, HASH);
332 tb->tbl_coeffsize = lookat;
333 tb->tbl_max = 7; /* it's a normal associative array */
334 tb->tbl_dosplit = tb->tbl_max * FILLPCT / 100;
337 tb->tbl_max = 127; /* it's a symbol table */
338 tb->tbl_dosplit = 128; /* so never split */
344 (void)hiterinit(tb); /* so each() will start off right */
354 str_free(hent->hent_val);
355 Safefree(hent->hent_key);
365 str_2static(hent->hent_val); /* free between statements */
366 Safefree(hent->hent_key);
377 hfreeentries(tb,dodbm);
381 (void)bzero((char*)tb->tbl_array, (tb->tbl_max + 1) * sizeof(HENT*));
386 hfreeentries(tb,dodbm)
391 register HENT *ohent = Null(HENT*);
402 if (!tb || !tb->tbl_array)
405 if ((old_dbm = tb->tbl_dbm) && dodbm) {
406 while (dkey = dbm_firstkey(tb->tbl_dbm), dkey.dptr) {
410 nextdkey = dbm_nextkey(tb->tbl_dbm, dkey);
412 nextdkey = dbm_nextkey(tb->tbl_dbm);
415 nextdkey = nextkey(dkey);
417 dbm_delete(tb->tbl_dbm,dkey);
419 } while (dkey.dptr); /* one way or another, this works */
422 tb->tbl_dbm = 0; /* now clear just cache */
425 while (hent = hiternext(tb)) { /* concise but not very efficient */
431 tb->tbl_dbm = old_dbm;
442 hfreeentries(tb,dodbm);
443 Safefree(tb->tbl_array);
452 tb->tbl_eiter = Null(HENT*);
460 register HENT *entry;
465 entry = tb->tbl_eiter;
471 key.dptr = entry->hent_key;
472 key.dsize = entry->hent_klen;
473 key = dbm_nextkey(tb->tbl_dbm, key);
475 key = dbm_nextkey(tb->tbl_dbm);
478 key.dptr = entry->hent_key;
479 key.dsize = entry->hent_klen;
484 Newz(504,entry, 1, HENT);
485 tb->tbl_eiter = entry;
486 key = dbm_firstkey(tb->tbl_dbm);
488 entry->hent_key = key.dptr;
489 entry->hent_klen = key.dsize;
492 str_free(entry->hent_val);
494 tb->tbl_eiter = Null(HENT*);
501 Newz(506,tb->tbl_array, tb->tbl_max + 1, HENT*);
504 entry = entry->hent_next;
507 if (tb->tbl_riter > tb->tbl_max) {
511 entry = tb->tbl_array[tb->tbl_riter];
515 tb->tbl_eiter = entry;
520 hiterkey(entry,retlen)
521 register HENT *entry;
524 *retlen = entry->hent_klen;
525 return entry->hent_key;
531 register HENT *entry;
537 key.dptr = entry->hent_key;
538 key.dsize = entry->hent_klen;
539 content = dbm_fetch(tb->tbl_dbm,key);
540 if (!entry->hent_val)
541 entry->hent_val = Str_new(62,0);
542 str_nset(entry->hent_val,content.dptr,content.dsize);
545 return entry->hent_val;
549 #if defined(FCNTL) && ! defined(O_CREAT)
560 #define O_CREAT 01000
564 static int dbmrefcnt = 0;
568 hdbmopen(tb,fname,mode)
576 if (tb->tbl_dbm) /* never really closed it */
583 hclear(tb, FALSE); /* clear cache */
586 tb->tbl_dbm = dbm_open(fname, O_RDWR|O_CREAT, mode);
588 tb->tbl_dbm = dbm_open(fname, O_RDWR, mode);
590 tb->tbl_dbm = dbm_open(fname, O_RDONLY, mode);
593 fatal("Old dbm can only open one database");
594 sprintf(buf,"%s.dir",fname);
595 if (stat(buf, &statbuf) < 0) {
596 if (mode < 0 || close(creat(buf,mode)) < 0)
598 sprintf(buf,"%s.pag",fname);
599 if (close(creat(buf,mode)) < 0)
602 tb->tbl_dbm = dbminit(fname) >= 0;
604 if (!tb->tbl_array && tb->tbl_dbm != 0)
605 Newz(507,tb->tbl_array, tb->tbl_max + 1, HENT*);
606 return tb->tbl_dbm != 0;
613 if (tb && tb->tbl_dbm) {
615 dbm_close(tb->tbl_dbm);
618 /* dbmrefcnt--; */ /* doesn't work, rats */
622 warn("Close on unopened dbm file");
626 hdbmstore(tb,key,klen,str)
632 datum dkey, dcontent;
635 if (!tb || !tb->tbl_dbm)
639 dcontent.dptr = str_get(str);
640 dcontent.dsize = str->str_cur;
641 error = dbm_store(tb->tbl_dbm, dkey, dcontent, DBM_REPLACE);
644 fatal("No write permission to dbm file");
645 warn("dbm store returned %d, errno %d, key \"%s\"",error,errno,key);
647 dbm_clearerr(tb->tbl_dbm);
652 #endif /* SOME_DBM */