1 /* $Header: hash.c,v 3.0.1.5 90/08/13 22:18:27 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.5 90/08/13 22:18:27 lwall
10 * patch28: defined(@array) and defined(%array) didn't work right
12 * Revision 3.0.1.4 90/08/09 03:50:22 lwall
13 * patch19: dbmopen(name, 'filename', undef) now refrains from creating
15 * Revision 3.0.1.3 90/03/27 15:59:09 lwall
16 * patch16: @dbmvalues{'foo','bar'} could use the same cache entry for both values
18 * Revision 3.0.1.2 89/12/21 20:03:39 lwall
19 * patch7: errno may now be a macro with an lvalue
21 * Revision 3.0.1.1 89/11/11 04:34:18 lwall
22 * patch2: CX/UX needed to set the key each time in associative iterators
24 * Revision 3.0 89/10/18 15:18:32 lwall
32 static char coeff[] = {
33 61,59,53,47,43,41,37,31,29,23,17,13,11,7,3,1,
34 61,59,53,47,43,41,37,31,29,23,17,13,11,7,3,1,
35 61,59,53,47,43,41,37,31,29,23,17,13,11,7,3,1,
36 61,59,53,47,43,41,37,31,29,23,17,13,11,7,3,1,
37 61,59,53,47,43,41,37,31,29,23,17,13,11,7,3,1,
38 61,59,53,47,43,41,37,31,29,23,17,13,11,7,3,1,
39 61,59,53,47,43,41,37,31,29,23,17,13,11,7,3,1,
40 61,59,53,47,43,41,37,31,29,23,17,13,11,7,3,1};
43 hfetch(tb,key,klen,lval)
63 Newz(503,tb->tbl_array, tb->tbl_max + 1, HENT*);
68 /* The hash function we use on symbols has to be equal to the first
69 * character when taken modulo 128, so that str_reset() can be implemented
70 * efficiently. We throw in the second character and the last character
71 * (times 128) so that long chains of identifiers starting with the
72 * same letter don't have to be strEQ'ed within hfetch(), since it
73 * compares hash values before trying strEQ().
75 if (!tb->tbl_coeffsize)
76 hash = *key + 128 * key[1] + 128 * key[klen-1]; /* assuming klen > 0 */
77 else { /* use normal coefficients */
78 if (klen < tb->tbl_coeffsize)
81 maxi = tb->tbl_coeffsize;
82 for (s=key, i=0, hash = 0;
84 s++, i++, hash *= 5) {
85 hash += *s * coeff[i];
89 entry = tb->tbl_array[hash & tb->tbl_max];
90 for (; entry; entry = entry->hent_next) {
91 if (entry->hent_hash != hash) /* strings can't be equal */
93 if (entry->hent_klen != klen)
95 if (bcmp(entry->hent_key,key,klen)) /* is this it? */
97 return entry->hent_val;
103 dcontent = dbm_fetch(tb->tbl_dbm,dkey);
104 if (dcontent.dptr) { /* found one */
105 str = Str_new(60,dcontent.dsize);
106 str_nset(str,dcontent.dptr,dcontent.dsize);
107 hstore(tb,key,klen,str,hash); /* cache it */
112 if (lval) { /* gonna assign to this, so it better be there */
114 hstore(tb,key,klen,str,hash);
121 hstore(tb,key,klen,val,hash)
130 register HENT *entry;
131 register HENT **oentry;
139 else if (!tb->tbl_coeffsize)
140 hash = *key + 128 * key[1] + 128 * key[klen-1];
141 else { /* use normal coefficients */
142 if (klen < tb->tbl_coeffsize)
145 maxi = tb->tbl_coeffsize;
146 for (s=key, i=0, hash = 0;
148 s++, i++, hash *= 5) {
149 hash += *s * coeff[i];
154 Newz(505,tb->tbl_array, tb->tbl_max + 1, HENT*);
156 oentry = &(tb->tbl_array[hash & tb->tbl_max]);
159 for (entry = *oentry; entry; i=0, entry = entry->hent_next) {
160 if (entry->hent_hash != hash) /* strings can't be equal */
162 if (entry->hent_klen != klen)
164 if (bcmp(entry->hent_key,key,klen)) /* is this it? */
166 Safefree(entry->hent_val);
167 entry->hent_val = val;
170 New(501,entry, 1, HENT);
172 entry->hent_klen = klen;
173 entry->hent_key = nsavestr(key,klen);
174 entry->hent_val = val;
175 entry->hent_hash = hash;
176 entry->hent_next = *oentry;
179 /* hdbmstore not necessary here because it's called from stabset() */
181 if (i) { /* initial entry? */
184 if (tb->tbl_dbm && tb->tbl_max >= DBM_CACHE_MAX)
187 if (tb->tbl_fill > tb->tbl_dosplit)
191 else if (tb->tbl_dbm) { /* is this just a cache for dbm file? */
192 void hentdelayfree();
194 entry = tb->tbl_array[hash & tb->tbl_max];
195 oentry = &entry->hent_next;
197 while (entry) { /* trim chain down to 1 entry */
198 *oentry = entry->hent_next;
199 hentdelayfree(entry); /* no doubt they'll want this next. */
217 register HENT *entry;
218 register HENT **oentry;
225 if (!tb || !tb->tbl_array)
227 if (!tb->tbl_coeffsize)
228 hash = *key + 128 * key[1] + 128 * key[klen-1];
229 else { /* use normal coefficients */
230 if (klen < tb->tbl_coeffsize)
233 maxi = tb->tbl_coeffsize;
234 for (s=key, i=0, hash = 0;
236 s++, i++, hash *= 5) {
237 hash += *s * coeff[i];
241 oentry = &(tb->tbl_array[hash & tb->tbl_max]);
244 for (; entry; i=0, oentry = &entry->hent_next, entry = *oentry) {
245 if (entry->hent_hash != hash) /* strings can't be equal */
247 if (entry->hent_klen != klen)
249 if (bcmp(entry->hent_key,key,klen)) /* is this it? */
251 *oentry = entry->hent_next;
252 str = str_static(entry->hent_val);
261 dbm_delete(tb->tbl_dbm,dkey);
277 int oldsize = tb->tbl_max + 1;
278 register int newsize = oldsize * 2;
282 register HENT *entry;
283 register HENT **oentry;
286 Renew(a, newsize, HENT*);
287 Zero(&a[oldsize], oldsize, HENT*); /* zero 2nd half*/
288 tb->tbl_max = --newsize;
289 tb->tbl_dosplit = tb->tbl_max * FILLPCT / 100;
292 for (i=0; i<oldsize; i++,a++) {
293 if (!*a) /* non-existent */
296 for (oentry = a, entry = *a; entry; entry = *oentry) {
297 if ((entry->hent_hash & newsize) != i) {
298 *oentry = entry->hent_next;
299 entry->hent_next = *b;
306 oentry = &entry->hent_next;
308 if (!*a) /* everything moved */
319 Newz(502,tb, 1, HASH);
321 tb->tbl_coeffsize = lookat;
322 tb->tbl_max = 7; /* it's a normal associative array */
323 tb->tbl_dosplit = tb->tbl_max * FILLPCT / 100;
326 tb->tbl_max = 127; /* it's a symbol table */
327 tb->tbl_dosplit = 128; /* so never split */
333 (void)hiterinit(tb); /* so each() will start off right */
343 str_free(hent->hent_val);
344 Safefree(hent->hent_key);
354 str_2static(hent->hent_val); /* free between statements */
355 Safefree(hent->hent_key);
364 register HENT *ohent = Null(HENT*);
366 if (!tb || !tb->tbl_array)
369 while (hent = hiternext(tb)) { /* concise but not very efficient */
376 (void)bzero((char*)tb->tbl_array, (tb->tbl_max + 1) * sizeof(HENT*));
385 register HENT *ohent = Null(HENT*);
390 while (hent = hiternext(tb)) {
395 Safefree(tb->tbl_array);
404 tb->tbl_eiter = Null(HENT*);
412 register HENT *entry;
417 entry = tb->tbl_eiter;
423 key.dptr = entry->hent_key;
424 key.dsize = entry->hent_klen;
425 key = dbm_nextkey(tb->tbl_dbm, key);
427 key = dbm_nextkey(tb->tbl_dbm);
430 key.dptr = entry->hent_key;
431 key.dsize = entry->hent_klen;
436 Newz(504,entry, 1, HENT);
437 tb->tbl_eiter = entry;
438 key = dbm_firstkey(tb->tbl_dbm);
440 entry->hent_key = key.dptr;
441 entry->hent_klen = key.dsize;
444 str_free(entry->hent_val);
446 tb->tbl_eiter = Null(HENT*);
453 Newz(506,tb->tbl_array, tb->tbl_max + 1, HENT*);
456 entry = entry->hent_next;
459 if (tb->tbl_riter > tb->tbl_max) {
463 entry = tb->tbl_array[tb->tbl_riter];
467 tb->tbl_eiter = entry;
472 hiterkey(entry,retlen)
473 register HENT *entry;
476 *retlen = entry->hent_klen;
477 return entry->hent_key;
483 register HENT *entry;
489 key.dptr = entry->hent_key;
490 key.dsize = entry->hent_klen;
491 content = dbm_fetch(tb->tbl_dbm,key);
492 if (!entry->hent_val)
493 entry->hent_val = Str_new(62,0);
494 str_nset(entry->hent_val,content.dptr,content.dsize);
497 return entry->hent_val;
501 #if defined(FCNTL) && ! defined(O_CREAT)
512 #define O_CREAT 01000
516 static int dbmrefcnt = 0;
520 hdbmopen(tb,fname,mode)
528 if (tb->tbl_dbm) /* never really closed it */
538 tb->tbl_dbm = dbm_open(fname, O_RDWR|O_CREAT, mode);
540 tb->tbl_dbm = dbm_open(fname, O_RDWR, mode);
543 fatal("Old dbm can only open one database");
544 sprintf(buf,"%s.dir",fname);
545 if (stat(buf, &statbuf) < 0) {
546 if (mode < 0 || close(creat(buf,mode)) < 0)
548 sprintf(buf,"%s.pag",fname);
549 if (close(creat(buf,mode)) < 0)
552 tb->tbl_dbm = dbminit(fname) >= 0;
554 return tb->tbl_dbm != 0;
561 if (tb && tb->tbl_dbm) {
563 dbm_close(tb->tbl_dbm);
566 /* dbmrefcnt--; */ /* doesn't work, rats */
570 warn("Close on unopened dbm file");
574 hdbmstore(tb,key,klen,str)
580 datum dkey, dcontent;
583 if (!tb || !tb->tbl_dbm)
587 dcontent.dptr = str_get(str);
588 dcontent.dsize = str->str_cur;
589 error = dbm_store(tb->tbl_dbm, dkey, dcontent, DBM_REPLACE);
592 fatal("No write permission to dbm file");
593 warn("dbm store returned %d, errno %d, key \"%s\"",error,errno,key);
595 dbm_clearerr(tb->tbl_dbm);
600 #endif /* SOME_DBM */