xref: /titanic_51/usr/src/common/ficl/hash.c (revision a1bf3f785ae05c419b339c3a2061f2b18c024f61)
1*a1bf3f78SToomas Soome #include "ficl.h"
2*a1bf3f78SToomas Soome 
3*a1bf3f78SToomas Soome #define	FICL_ASSERT_PHASH(hash, expression)	FICL_ASSERT(NULL, expression)
4*a1bf3f78SToomas Soome 
5*a1bf3f78SToomas Soome /*
6*a1bf3f78SToomas Soome  * h a s h F o r g e t
7*a1bf3f78SToomas Soome  * Unlink all words in the hash that have addresses greater than or
8*a1bf3f78SToomas Soome  * equal to the address supplied. Implementation factor for FORGET
9*a1bf3f78SToomas Soome  * and MARKER.
10*a1bf3f78SToomas Soome  */
11*a1bf3f78SToomas Soome void
12*a1bf3f78SToomas Soome ficlHashForget(ficlHash *hash, void *where)
13*a1bf3f78SToomas Soome {
14*a1bf3f78SToomas Soome 	ficlWord *pWord;
15*a1bf3f78SToomas Soome 	unsigned i;
16*a1bf3f78SToomas Soome 
17*a1bf3f78SToomas Soome 	FICL_ASSERT_PHASH(hash, hash);
18*a1bf3f78SToomas Soome 	FICL_ASSERT_PHASH(hash, where);
19*a1bf3f78SToomas Soome 
20*a1bf3f78SToomas Soome 	for (i = 0; i < hash->size; i++) {
21*a1bf3f78SToomas Soome 		pWord = hash->table[i];
22*a1bf3f78SToomas Soome 
23*a1bf3f78SToomas Soome 		while ((void *)pWord >= where) {
24*a1bf3f78SToomas Soome 			pWord = pWord->link;
25*a1bf3f78SToomas Soome 		}
26*a1bf3f78SToomas Soome 
27*a1bf3f78SToomas Soome 		hash->table[i] = pWord;
28*a1bf3f78SToomas Soome 	}
29*a1bf3f78SToomas Soome }
30*a1bf3f78SToomas Soome 
31*a1bf3f78SToomas Soome /*
32*a1bf3f78SToomas Soome  * h a s h H a s h C o d e
33*a1bf3f78SToomas Soome  *
34*a1bf3f78SToomas Soome  * Generate a 16 bit hashcode from a character string using a rolling
35*a1bf3f78SToomas Soome  * shift and add stolen from PJ Weinberger of Bell Labs fame. Case folds
36*a1bf3f78SToomas Soome  * the name before hashing it...
37*a1bf3f78SToomas Soome  * N O T E : If string has zero length, returns zero.
38*a1bf3f78SToomas Soome  */
39*a1bf3f78SToomas Soome ficlUnsigned16
40*a1bf3f78SToomas Soome ficlHashCode(ficlString s)
41*a1bf3f78SToomas Soome {
42*a1bf3f78SToomas Soome 	/* hashPJW */
43*a1bf3f78SToomas Soome 	ficlUnsigned8 *trace;
44*a1bf3f78SToomas Soome 	ficlUnsigned16 code = (ficlUnsigned16)s.length;
45*a1bf3f78SToomas Soome 	ficlUnsigned16 shift = 0;
46*a1bf3f78SToomas Soome 
47*a1bf3f78SToomas Soome 	if (s.length == 0)
48*a1bf3f78SToomas Soome 		return (0);
49*a1bf3f78SToomas Soome 
50*a1bf3f78SToomas Soome 	/* changed to run without errors under Purify -- lch */
51*a1bf3f78SToomas Soome 	for (trace = (ficlUnsigned8 *)s.text;
52*a1bf3f78SToomas Soome 	    s.length && *trace; trace++, s.length--) {
53*a1bf3f78SToomas Soome 		code = (ficlUnsigned16)((code << 4) + tolower(*trace));
54*a1bf3f78SToomas Soome 		shift = (ficlUnsigned16)(code & 0xf000);
55*a1bf3f78SToomas Soome 		if (shift) {
56*a1bf3f78SToomas Soome 			code ^= (ficlUnsigned16)(shift >> 8);
57*a1bf3f78SToomas Soome 			code ^= (ficlUnsigned16)shift;
58*a1bf3f78SToomas Soome 		}
59*a1bf3f78SToomas Soome 	}
60*a1bf3f78SToomas Soome 
61*a1bf3f78SToomas Soome 	return ((ficlUnsigned16)code);
62*a1bf3f78SToomas Soome }
63*a1bf3f78SToomas Soome 
64*a1bf3f78SToomas Soome /*
65*a1bf3f78SToomas Soome  * h a s h I n s e r t W o r d
66*a1bf3f78SToomas Soome  * Put a word into the hash table using the word's hashcode as
67*a1bf3f78SToomas Soome  * an index (modulo the table size).
68*a1bf3f78SToomas Soome  */
69*a1bf3f78SToomas Soome void
70*a1bf3f78SToomas Soome ficlHashInsertWord(ficlHash *hash, ficlWord *word)
71*a1bf3f78SToomas Soome {
72*a1bf3f78SToomas Soome 	ficlWord **pList;
73*a1bf3f78SToomas Soome 
74*a1bf3f78SToomas Soome 	FICL_ASSERT_PHASH(hash, hash);
75*a1bf3f78SToomas Soome 	FICL_ASSERT_PHASH(hash, word);
76*a1bf3f78SToomas Soome 
77*a1bf3f78SToomas Soome 	if (hash->size == 1) {
78*a1bf3f78SToomas Soome 		pList = hash->table;
79*a1bf3f78SToomas Soome 	} else {
80*a1bf3f78SToomas Soome 		pList = hash->table + (word->hash % hash->size);
81*a1bf3f78SToomas Soome 	}
82*a1bf3f78SToomas Soome 
83*a1bf3f78SToomas Soome 	word->link = *pList;
84*a1bf3f78SToomas Soome 	*pList = word;
85*a1bf3f78SToomas Soome }
86*a1bf3f78SToomas Soome 
87*a1bf3f78SToomas Soome /*
88*a1bf3f78SToomas Soome  * h a s h L o o k u p
89*a1bf3f78SToomas Soome  * Find a name in the hash table given the hashcode and text of the name.
90*a1bf3f78SToomas Soome  * Returns the address of the corresponding ficlWord if found,
91*a1bf3f78SToomas Soome  * otherwise NULL.
92*a1bf3f78SToomas Soome  * Note: outer loop on link field supports inheritance in wordlists.
93*a1bf3f78SToomas Soome  * It's not part of ANS Forth - Ficl only. hashReset creates wordlists
94*a1bf3f78SToomas Soome  * with NULL link fields.
95*a1bf3f78SToomas Soome  */
96*a1bf3f78SToomas Soome ficlWord *
97*a1bf3f78SToomas Soome ficlHashLookup(ficlHash *hash, ficlString name, ficlUnsigned16 hashCode)
98*a1bf3f78SToomas Soome {
99*a1bf3f78SToomas Soome 	ficlUnsigned nCmp = name.length;
100*a1bf3f78SToomas Soome 	ficlWord *word;
101*a1bf3f78SToomas Soome 	ficlUnsigned16 hashIdx;
102*a1bf3f78SToomas Soome 
103*a1bf3f78SToomas Soome 	if (nCmp > FICL_NAME_LENGTH)
104*a1bf3f78SToomas Soome 		nCmp = FICL_NAME_LENGTH;
105*a1bf3f78SToomas Soome 
106*a1bf3f78SToomas Soome 	for (; hash != NULL; hash = hash->link) {
107*a1bf3f78SToomas Soome 		if (hash->size > 1)
108*a1bf3f78SToomas Soome 			hashIdx = (ficlUnsigned16)(hashCode % hash->size);
109*a1bf3f78SToomas Soome 		else /* avoid the modulo op for single threaded lists */
110*a1bf3f78SToomas Soome 			hashIdx = 0;
111*a1bf3f78SToomas Soome 
112*a1bf3f78SToomas Soome 		for (word = hash->table[hashIdx]; word; word = word->link) {
113*a1bf3f78SToomas Soome 			if ((word->length == name.length) &&
114*a1bf3f78SToomas Soome 			    (!ficlStrincmp(name.text, word->name, nCmp)))
115*a1bf3f78SToomas Soome 				return (word);
116*a1bf3f78SToomas Soome #if FICL_ROBUST
117*a1bf3f78SToomas Soome 			FICL_ASSERT_PHASH(hash, word != word->link);
118*a1bf3f78SToomas Soome #endif
119*a1bf3f78SToomas Soome 		}
120*a1bf3f78SToomas Soome 	}
121*a1bf3f78SToomas Soome 
122*a1bf3f78SToomas Soome 	return (NULL);
123*a1bf3f78SToomas Soome }
124*a1bf3f78SToomas Soome 
125*a1bf3f78SToomas Soome /*
126*a1bf3f78SToomas Soome  * h a s h R e s e t
127*a1bf3f78SToomas Soome  * Initialize a ficlHash to empty state.
128*a1bf3f78SToomas Soome  */
129*a1bf3f78SToomas Soome void
130*a1bf3f78SToomas Soome ficlHashReset(ficlHash *hash)
131*a1bf3f78SToomas Soome {
132*a1bf3f78SToomas Soome 	unsigned i;
133*a1bf3f78SToomas Soome 
134*a1bf3f78SToomas Soome 	FICL_ASSERT_PHASH(hash, hash);
135*a1bf3f78SToomas Soome 
136*a1bf3f78SToomas Soome 	for (i = 0; i < hash->size; i++) {
137*a1bf3f78SToomas Soome 		hash->table[i] = NULL;
138*a1bf3f78SToomas Soome 	}
139*a1bf3f78SToomas Soome 
140*a1bf3f78SToomas Soome 	hash->link = NULL;
141*a1bf3f78SToomas Soome 	hash->name = NULL;
142*a1bf3f78SToomas Soome }
143