1 /* Hash tables for Objective C internal structures
2 Copyright (C) 1993, 1996, 1997 Free Software Foundation, Inc.
4 This file is part of GNU CC.
6 GNU CC is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 GNU CC is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU CC; see the file COPYING. If not, write to
18 the Free Software Foundation, 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
21 /* As a special exception, if you link this library with files
22 compiled with GCC to produce an executable, this does not cause
23 the resulting executable to be covered by the GNU General Public License.
24 This exception does not however invalidate any other reasons why
25 the executable file might be covered by the GNU General Public License. */
31 #include "runtime.h" /* for DEBUG_PRINTF */
33 /* These two macros determine when a hash table is full and
34 by how much it should be expanded respectively.
36 These equations are percentages. */
37 #define FULLNESS(cache) \
38 ((((cache)->size * 75) / 100) <= (cache)->used)
39 #define EXPANSION(cache) \
43 hash_new (unsigned int size
, hash_func_type hash_func
,
44 compare_func_type compare_func
)
48 /* Pass me a value greater than 0 and a power of 2. */
50 assert (!(size
& (size
- 1)));
52 /* Allocate the cache structure. calloc insures
53 its initialization for default values. */
54 cache
= (cache_ptr
) objc_calloc (1, sizeof (struct cache
));
57 /* Allocate the array of buckets for the cache.
58 calloc initializes all of the pointers to NULL. */
60 = (node_ptr
*) objc_calloc (size
, sizeof (node_ptr
));
61 assert (cache
->node_table
);
65 /* This should work for all processor architectures? */
66 cache
->mask
= (size
- 1);
68 /* Store the hashing function so that codes can be computed. */
69 cache
->hash_func
= hash_func
;
71 /* Store the function that compares hash keys to
72 determine if they are equal. */
73 cache
->compare_func
= compare_func
;
80 hash_delete (cache_ptr cache
)
86 /* Purge all key/value pairs from the table. */
87 /* Step through the nodes one by one and remove every node WITHOUT
88 using hash_next. this makes hash_delete much more efficient. */
89 for (i
= 0;i
< cache
->size
;i
++) {
90 if ((node
= cache
->node_table
[i
])) {
91 /* an entry in the hash table has been found, now step through the
92 nodes next in the list and free them. */
93 while ((next_node
= node
->next
)) {
94 hash_remove (cache
,node
->key
);
98 hash_remove (cache
,node
->key
);
102 /* Release the array of nodes and the cache itself. */
103 objc_free(cache
->node_table
);
109 hash_add (cache_ptr
*cachep
, const void *key
, void *value
)
111 size_t indx
= (*(*cachep
)->hash_func
)(*cachep
, key
);
112 node_ptr node
= (node_ptr
) objc_calloc (1, sizeof (struct cache_node
));
117 /* Initialize the new node. */
120 node
->next
= (*cachep
)->node_table
[indx
];
123 Check the list for another key. */
125 { node_ptr node1
= (*cachep
)->node_table
[indx
];
129 assert (node1
->key
!= key
);
135 /* Install the node as the first element on the list. */
136 (*cachep
)->node_table
[indx
] = node
;
138 /* Bump the number of entries in the cache. */
141 /* Check the hash table's fullness. We're going
142 to expand if it is above the fullness level. */
143 if (FULLNESS (*cachep
)) {
145 /* The hash table has reached its fullness level. Time to
148 I'm using a slow method here but is built on other
149 primitive functions thereby increasing its
151 node_ptr node1
= NULL
;
152 cache_ptr
new = hash_new (EXPANSION (*cachep
),
153 (*cachep
)->hash_func
,
154 (*cachep
)->compare_func
);
156 DEBUG_PRINTF ("Expanding cache %#x from %d to %d\n",
157 *cachep
, (*cachep
)->size
, new->size
);
159 /* Copy the nodes from the first hash table to the new one. */
160 while ((node1
= hash_next (*cachep
, node1
)))
161 hash_add (&new, node1
->key
, node1
->value
);
163 /* Trash the old cache. */
164 hash_delete (*cachep
);
166 /* Return a pointer to the new hash table. */
173 hash_remove (cache_ptr cache
, const void *key
)
175 size_t indx
= (*cache
->hash_func
)(cache
, key
);
176 node_ptr node
= cache
->node_table
[indx
];
179 /* We assume there is an entry in the table. Error if it is not. */
182 /* Special case. First element is the key/value pair to be removed. */
183 if ((*cache
->compare_func
)(node
->key
, key
)) {
184 cache
->node_table
[indx
] = node
->next
;
188 /* Otherwise, find the hash entry. */
189 node_ptr prev
= node
;
194 if ((*cache
->compare_func
)(node
->key
, key
)) {
195 prev
->next
= node
->next
, removed
= YES
;
198 prev
= node
, node
= node
->next
;
199 } while (!removed
&& node
);
203 /* Decrement the number of entries in the hash table. */
209 hash_next (cache_ptr cache
, node_ptr node
)
211 /* If the scan is being started then reset the last node
212 visitied pointer and bucket index. */
214 cache
->last_bucket
= 0;
216 /* If there is a node visited last then check for another
217 entry in the same bucket; Otherwise step to the next bucket. */
220 /* There is a node which follows the last node
221 returned. Step to that node and retun it. */
224 ++cache
->last_bucket
;
227 /* If the list isn't exhausted then search the buckets for
229 if (cache
->last_bucket
< cache
->size
) {
230 /* Scan the remainder of the buckets looking for an entry
231 at the head of the list. Return the first item found. */
232 while (cache
->last_bucket
< cache
->size
)
233 if (cache
->node_table
[cache
->last_bucket
])
234 return cache
->node_table
[cache
->last_bucket
];
236 ++cache
->last_bucket
;
238 /* No further nodes were found in the hash table. */
245 /* Given KEY, return corresponding value for it in CACHE.
246 Return NULL if the KEY is not recorded. */
249 hash_value_for_key (cache_ptr cache
, const void *key
)
251 node_ptr node
= cache
->node_table
[(*cache
->hash_func
)(cache
, key
)];
256 if ((*cache
->compare_func
)(node
->key
, key
)) {
257 retval
= node
->value
;
261 } while (!retval
&& node
);
266 /* Given KEY, return YES if it exists in the CACHE.
267 Return NO if it does not */
270 hash_is_key_in_hash (cache_ptr cache
, const void *key
)
272 node_ptr node
= cache
->node_table
[(*cache
->hash_func
)(cache
, key
)];
276 if ((*cache
->compare_func
)(node
->key
, key
))