1 /* $Header: hash.c,v 3.0.1.3 90/03/27 15:59:09 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.3 90/03/27 15:59:09 lwall
10 * patch16: @dbmvalues{'foo','bar'} could use the same cache entry for both values
12 * Revision 3.0.1.2 89/12/21 20:03:39 lwall
13 * patch7: errno may now be a macro with an lvalue
15 * Revision 3.0.1.1 89/11/11 04:34:18 lwall
16 * patch2: CX/UX needed to set the key each time in associative iterators
18 * Revision 3.0 89/10/18 15:18:32 lwall
27 hfetch(tb,key,klen,lval)
46 /* The hash function we use on symbols has to be equal to the first
47 * character when taken modulo 128, so that str_reset() can be implemented
48 * efficiently. We throw in the second character and the last character
49 * (times 128) so that long chains of identifiers starting with the
50 * same letter don't have to be strEQ'ed within hfetch(), since it
51 * compares hash values before trying strEQ().
53 if (!tb->tbl_coeffsize)
54 hash = *key + 128 * key[1] + 128 * key[klen-1]; /* assuming klen > 0 */
55 else { /* use normal coefficients */
56 if (klen < tb->tbl_coeffsize)
59 maxi = tb->tbl_coeffsize;
60 for (s=key, i=0, hash = 0;
62 s++, i++, hash *= 5) {
63 hash += *s * coeff[i];
67 entry = tb->tbl_array[hash & tb->tbl_max];
68 for (; entry; entry = entry->hent_next) {
69 if (entry->hent_hash != hash) /* strings can't be equal */
71 if (entry->hent_klen != klen)
73 if (bcmp(entry->hent_key,key,klen)) /* is this it? */
75 return entry->hent_val;
81 dcontent = dbm_fetch(tb->tbl_dbm,dkey);
82 if (dcontent.dptr) { /* found one */
83 str = Str_new(60,dcontent.dsize);
84 str_nset(str,dcontent.dptr,dcontent.dsize);
85 hstore(tb,key,klen,str,hash); /* cache it */
90 if (lval) { /* gonna assign to this, so it better be there */
92 hstore(tb,key,klen,str,hash);
99 hstore(tb,key,klen,val,hash)
108 register HENT *entry;
109 register HENT **oentry;
117 else if (!tb->tbl_coeffsize)
118 hash = *key + 128 * key[1] + 128 * key[klen-1];
119 else { /* use normal coefficients */
120 if (klen < tb->tbl_coeffsize)
123 maxi = tb->tbl_coeffsize;
124 for (s=key, i=0, hash = 0;
126 s++, i++, hash *= 5) {
127 hash += *s * coeff[i];
131 oentry = &(tb->tbl_array[hash & tb->tbl_max]);
134 for (entry = *oentry; entry; i=0, entry = entry->hent_next) {
135 if (entry->hent_hash != hash) /* strings can't be equal */
137 if (entry->hent_klen != klen)
139 if (bcmp(entry->hent_key,key,klen)) /* is this it? */
141 Safefree(entry->hent_val);
142 entry->hent_val = val;
145 New(501,entry, 1, HENT);
147 entry->hent_klen = klen;
148 entry->hent_key = nsavestr(key,klen);
149 entry->hent_val = val;
150 entry->hent_hash = hash;
151 entry->hent_next = *oentry;
154 /* hdbmstore not necessary here because it's called from stabset() */
156 if (i) { /* initial entry? */
159 if (tb->tbl_dbm && tb->tbl_max >= DBM_CACHE_MAX)
162 if (tb->tbl_fill > tb->tbl_dosplit)
166 else if (tb->tbl_dbm) { /* is this just a cache for dbm file? */
167 void hentdelayfree();
169 entry = tb->tbl_array[hash & tb->tbl_max];
170 oentry = &entry->hent_next;
172 while (entry) { /* trim chain down to 1 entry */
173 *oentry = entry->hent_next;
174 hentdelayfree(entry); /* no doubt they'll want this next. */
192 register HENT *entry;
193 register HENT **oentry;
202 if (!tb->tbl_coeffsize)
203 hash = *key + 128 * key[1] + 128 * key[klen-1];
204 else { /* use normal coefficients */
205 if (klen < tb->tbl_coeffsize)
208 maxi = tb->tbl_coeffsize;
209 for (s=key, i=0, hash = 0;
211 s++, i++, hash *= 5) {
212 hash += *s * coeff[i];
216 oentry = &(tb->tbl_array[hash & tb->tbl_max]);
219 for (; entry; i=0, oentry = &entry->hent_next, entry = *oentry) {
220 if (entry->hent_hash != hash) /* strings can't be equal */
222 if (entry->hent_klen != klen)
224 if (bcmp(entry->hent_key,key,klen)) /* is this it? */
226 *oentry = entry->hent_next;
227 str = str_static(entry->hent_val);
236 dbm_delete(tb->tbl_dbm,dkey);
252 int oldsize = tb->tbl_max + 1;
253 register int newsize = oldsize * 2;
257 register HENT *entry;
258 register HENT **oentry;
261 Renew(a, newsize, HENT*);
262 Zero(&a[oldsize], oldsize, HENT*); /* zero 2nd half*/
263 tb->tbl_max = --newsize;
264 tb->tbl_dosplit = tb->tbl_max * FILLPCT / 100;
267 for (i=0; i<oldsize; i++,a++) {
268 if (!*a) /* non-existent */
271 for (oentry = a, entry = *a; entry; entry = *oentry) {
272 if ((entry->hent_hash & newsize) != i) {
273 *oentry = entry->hent_next;
274 entry->hent_next = *b;
281 oentry = &entry->hent_next;
283 if (!*a) /* everything moved */
294 Newz(502,tb, 1, HASH);
296 tb->tbl_coeffsize = lookat;
297 tb->tbl_max = 7; /* it's a normal associative array */
298 tb->tbl_dosplit = tb->tbl_max * FILLPCT / 100;
301 tb->tbl_max = 127; /* it's a symbol table */
302 tb->tbl_dosplit = 128; /* so never split */
304 Newz(503,tb->tbl_array, tb->tbl_max + 1, HENT*);
309 (void)hiterinit(tb); /* so each() will start off right */
319 str_free(hent->hent_val);
320 Safefree(hent->hent_key);
330 str_2static(hent->hent_val); /* free between statements */
331 Safefree(hent->hent_key);
340 register HENT *ohent = Null(HENT*);
345 while (hent = hiternext(tb)) { /* concise but not very efficient */
352 (void)bzero((char*)tb->tbl_array, (tb->tbl_max + 1) * sizeof(HENT*));
361 register HENT *ohent = Null(HENT*);
366 while (hent = hiternext(tb)) {
371 Safefree(tb->tbl_array);
380 tb->tbl_eiter = Null(HENT*);
388 register HENT *entry;
393 entry = tb->tbl_eiter;
399 key.dptr = entry->hent_key;
400 key.dsize = entry->hent_klen;
401 key = dbm_nextkey(tb->tbl_dbm, key);
403 key = dbm_nextkey(tb->tbl_dbm);
406 key.dptr = entry->hent_key;
407 key.dsize = entry->hent_klen;
412 Newz(504,entry, 1, HENT);
413 tb->tbl_eiter = entry;
414 key = dbm_firstkey(tb->tbl_dbm);
416 entry->hent_key = key.dptr;
417 entry->hent_klen = key.dsize;
420 str_free(entry->hent_val);
422 tb->tbl_eiter = Null(HENT*);
430 entry = entry->hent_next;
433 if (tb->tbl_riter > tb->tbl_max) {
437 entry = tb->tbl_array[tb->tbl_riter];
441 tb->tbl_eiter = entry;
446 hiterkey(entry,retlen)
447 register HENT *entry;
450 *retlen = entry->hent_klen;
451 return entry->hent_key;
457 register HENT *entry;
463 key.dptr = entry->hent_key;
464 key.dsize = entry->hent_klen;
465 content = dbm_fetch(tb->tbl_dbm,key);
466 if (!entry->hent_val)
467 entry->hent_val = Str_new(62,0);
468 str_nset(entry->hent_val,content.dptr,content.dsize);
471 return entry->hent_val;
475 #if defined(FCNTL) && ! defined(O_CREAT)
486 #define O_CREAT 01000
490 static int dbmrefcnt = 0;
494 hdbmopen(tb,fname,mode)
502 if (tb->tbl_dbm) /* never really closed it */
509 tb->tbl_dbm = dbm_open(fname, O_RDWR|O_CREAT, mode);
510 if (!tb->tbl_dbm) /* oops, just try reading it */
511 tb->tbl_dbm = dbm_open(fname, O_RDONLY, mode);
514 fatal("Old dbm can only open one database");
515 sprintf(buf,"%s.dir",fname);
516 if (stat(buf, &statbuf) < 0) {
517 if (close(creat(buf,mode)) < 0)
519 sprintf(buf,"%s.pag",fname);
520 if (close(creat(buf,mode)) < 0)
523 tb->tbl_dbm = dbminit(fname) >= 0;
525 return tb->tbl_dbm != 0;
532 if (tb && tb->tbl_dbm) {
534 dbm_close(tb->tbl_dbm);
537 /* dbmrefcnt--; */ /* doesn't work, rats */
541 warn("Close on unopened dbm file");
545 hdbmstore(tb,key,klen,str)
551 datum dkey, dcontent;
554 if (!tb || !tb->tbl_dbm)
558 dcontent.dptr = str_get(str);
559 dcontent.dsize = str->str_cur;
560 error = dbm_store(tb->tbl_dbm, dkey, dcontent, DBM_REPLACE);
563 fatal("No write permission to dbm file");
564 warn("dbm store returned %d, errno %d, key \"%s\"",error,errno,key);
566 dbm_clearerr(tb->tbl_dbm);
571 #endif /* SOME_DBM */