00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "config.h"
00023 #include "system.h"
00024 #include "hashtable.h"
00025
00026
00027
00028
00029
00030
00031
00032
00033 static unsigned int calc_hash PARAMS ((const unsigned char *, unsigned int));
00034 static void ht_expand PARAMS ((hash_table *));
00035
00036
00037 #ifndef OBSTACK_CHUNK_SIZE
00038 #define OBSTACK_CHUNK_SIZE 0
00039 #endif
00040
00041 #ifndef OBSTACK_CHUNK_ALLOC
00042 #define OBSTACK_CHUNK_ALLOC xmalloc
00043 #endif
00044 #ifndef OBSTACK_CHUNK_FREE
00045 #define OBSTACK_CHUNK_FREE free
00046 #endif
00047
00048
00049 void
00050 gcc_obstack_init (obstack)
00051 struct obstack *obstack;
00052 {
00053 _obstack_begin (obstack, OBSTACK_CHUNK_SIZE, 0,
00054 (void *(*) PARAMS ((long))) OBSTACK_CHUNK_ALLOC,
00055 (void (*) PARAMS ((void *))) OBSTACK_CHUNK_FREE);
00056 }
00057
00058
00059
00060 static unsigned int
00061 calc_hash (str, len)
00062 const unsigned char *str;
00063 unsigned int len;
00064 {
00065 unsigned int n = len;
00066 unsigned int r = 0;
00067 #define HASHSTEP(r, c) ((r) * 67 + ((c) - 113));
00068
00069 while (n--)
00070 r = HASHSTEP (r, *str++);
00071
00072 return r + len;
00073 #undef HASHSTEP
00074 }
00075
00076
00077
00078 hash_table *
00079 ht_create (order)
00080 unsigned int order;
00081 {
00082 unsigned int nslots = 1 << order;
00083 hash_table *table;
00084
00085 table = (hash_table *) xmalloc (sizeof (hash_table));
00086 memset (table, 0, sizeof (hash_table));
00087
00088
00089 gcc_obstack_init (&table->stack);
00090 obstack_alignment_mask (&table->stack) = 0;
00091
00092 table->entries = (hashnode *) xcalloc (nslots, sizeof (hashnode));
00093 table->nslots = nslots;
00094 return table;
00095 }
00096
00097
00098
00099 void
00100 ht_destroy (table)
00101 hash_table *table;
00102 {
00103 obstack_free (&table->stack, NULL);
00104 free (table->entries);
00105 free (table);
00106 }
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116 hashnode
00117 ht_lookup (table, str, len, insert)
00118 hash_table *table;
00119 const unsigned char *str;
00120 unsigned int len;
00121 enum ht_lookup_option insert;
00122 {
00123 unsigned int hash = calc_hash (str, len);
00124 unsigned int hash2;
00125 unsigned int index;
00126 size_t sizemask;
00127 hashnode node;
00128
00129 sizemask = table->nslots - 1;
00130 index = hash & sizemask;
00131
00132
00133
00134 hash2 = ((hash * 17) & sizemask) | 1;
00135 table->searches++;
00136
00137 for (;;)
00138 {
00139 node = table->entries[index];
00140
00141 if (node == NULL)
00142 break;
00143
00144 if (node->hash_value == hash && HT_LEN (node) == len
00145 && !memcmp (HT_STR (node), str, len))
00146 {
00147 if (insert == HT_ALLOCED)
00148
00149
00150 obstack_free (&table->stack, (PTR) str);
00151 return node;
00152 }
00153
00154 index = (index + hash2) & sizemask;
00155 table->collisions++;
00156 }
00157
00158 if (insert == HT_NO_INSERT)
00159 return NULL;
00160
00161 node = (*table->alloc_node) (table);
00162 table->entries[index] = node;
00163
00164 HT_LEN (node) = len;
00165 node->hash_value = hash;
00166 if (insert == HT_ALLOC)
00167 HT_STR (node) = obstack_copy0 (&table->stack, str, len);
00168 else
00169 HT_STR (node) = str;
00170
00171 if (++table->nelements * 4 >= table->nslots * 3)
00172
00173 ht_expand (table);
00174
00175 return node;
00176 }
00177
00178
00179
00180 static void
00181 ht_expand (table)
00182 hash_table *table;
00183 {
00184 hashnode *nentries, *p, *limit;
00185 unsigned int size, sizemask;
00186
00187 size = table->nslots * 2;
00188 nentries = (hashnode *) xcalloc (size, sizeof (hashnode));
00189 sizemask = size - 1;
00190
00191 p = table->entries;
00192 limit = p + table->nslots;
00193 do
00194 if (*p)
00195 {
00196 unsigned int index, hash, hash2;
00197
00198 hash = (*p)->hash_value;
00199 hash2 = ((hash * 17) & sizemask) | 1;
00200 index = hash & sizemask;
00201
00202 for (;;)
00203 {
00204 if (! nentries[index])
00205 {
00206 nentries[index] = *p;
00207 break;
00208 }
00209
00210 index = (index + hash2) & sizemask;
00211 }
00212 }
00213 while (++p < limit);
00214
00215 free (table->entries);
00216 table->entries = nentries;
00217 table->nslots = size;
00218 }
00219
00220
00221
00222 void
00223 ht_forall (table, cb, v)
00224 hash_table *table;
00225 ht_cb cb;
00226 const PTR v;
00227 {
00228 hashnode *p, *limit;
00229
00230 p = table->entries;
00231 limit = p + table->nslots;
00232 do
00233 if (*p)
00234 {
00235 if ((*cb) (table->pfile, *p, v) == 0)
00236 break;
00237 }
00238 while (++p < limit);
00239 }
00240
00241
00242
00243 void
00244 ht_dump_statistics (table)
00245 hash_table *table;
00246 {
00247 size_t nelts, nids, overhead, headers;
00248 size_t total_bytes, longest, sum_of_squares;
00249 double exp_len, exp_len2, exp2_len;
00250 hashnode *p, *limit;
00251
00252 #define SCALE(x) ((unsigned long) ((x) < 1024*10 \
00253 ? (x) \
00254 : ((x) < 1024*1024*10 \
00255 ? (x) / 1024 \
00256 : (x) / (1024*1024))))
00257 #define LABEL(x) ((x) < 1024*10 ? ' ' : ((x) < 1024*1024*10 ? 'k' : 'M'))
00258
00259 total_bytes = longest = sum_of_squares = nids = 0;
00260 p = table->entries;
00261 limit = p + table->nslots;
00262 do
00263 if (*p)
00264 {
00265 size_t n = HT_LEN (*p);
00266
00267 total_bytes += n;
00268 sum_of_squares += n * n;
00269 if (n > longest)
00270 longest = n;
00271 nids++;
00272 }
00273 while (++p < limit);
00274
00275 nelts = table->nelements;
00276 overhead = obstack_memory_used (&table->stack) - total_bytes;
00277 headers = table->nslots * sizeof (hashnode);
00278
00279 fprintf (stderr, "\nString pool\nentries\t\t%lu\n",
00280 (unsigned long) nelts);
00281 fprintf (stderr, "identifiers\t%lu (%.2f%%)\n",
00282 (unsigned long) nids, nids * 100.0 / nelts);
00283 fprintf (stderr, "slots\t\t%lu\n",
00284 (unsigned long) table->nslots);
00285 fprintf (stderr, "bytes\t\t%lu%c (%lu%c overhead)\n",
00286 SCALE (total_bytes), LABEL (total_bytes),
00287 SCALE (overhead), LABEL (overhead));
00288 fprintf (stderr, "table size\t%lu%c\n",
00289 SCALE (headers), LABEL (headers));
00290
00291 exp_len = (double)total_bytes / (double)nelts;
00292 exp2_len = exp_len * exp_len;
00293 exp_len2 = (double) sum_of_squares / (double) nelts;
00294
00295 fprintf (stderr, "coll/search\t%.4f\n",
00296 (double) table->collisions / (double) table->searches);
00297 fprintf (stderr, "ins/search\t%.4f\n",
00298 (double) nelts / (double) table->searches);
00299 fprintf (stderr, "avg. entry\t%.2f bytes (+/- %.2f)\n",
00300 exp_len, approx_sqrt (exp_len2 - exp2_len));
00301 fprintf (stderr, "longest entry\t%lu\n",
00302 (unsigned long) longest);
00303 #undef SCALE
00304 #undef LABEL
00305 }
00306
00307
00308
00309 double
00310 approx_sqrt (x)
00311 double x;
00312 {
00313 double s, d;
00314
00315 if (x < 0)
00316 abort ();
00317 if (x == 0)
00318 return 0;
00319
00320 s = x;
00321 do
00322 {
00323 d = (s * s - x) / (2 * s);
00324 s -= d;
00325 }
00326 while (d > .0001);
00327 return s;
00328 }