source: trunk/third/gettext/lib/hash.c @ 16931

Revision 16931, 8.7 KB checked in by ghudson, 23 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r16930, which included commits to RCS files with non-trunk default branches.
Line 
1/* hash - implement simple hashing table with string based keys.
2   Copyright (C) 1994, 1995, 2000, 2001 Free Software Foundation, Inc.
3   Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, October 1994.
4
5   This program is free software; you can redistribute it and/or modify
6   it under the terms of the GNU General Public License as published by
7   the Free Software Foundation; either version 2, or (at your option)
8   any later version.
9
10   This program is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   GNU General Public License for more details.
14
15   You should have received a copy of the GNU General Public License
16   along with this program; if not, write to the Free Software Foundation,
17   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
18
19#if HAVE_CONFIG_H
20# include <config.h>
21#endif
22
23#if STDC_HEADERS
24# include <stdlib.h>
25#else
26# ifdef HAVE_MALLOC_H
27#  include <malloc.h>
28# endif
29#endif
30
31#ifdef HAVE_STRING_H
32# include <string.h>
33#else
34# include <strings.h>
35#endif
36
37#include <stdio.h>
38#include <sys/types.h>
39
40#if HAVE_OBSTACK
41# include <obstack.h>
42#else
43# include "obstack.h"
44#endif
45
46#if HAVE_VALUES_H
47# include <values.h>
48#endif
49
50#include "hash.h"
51
52#define obstack_chunk_alloc xmalloc
53#define obstack_chunk_free free
54
55#ifndef BITSPERBYTE
56# define BITSPERBYTE 8
57#endif
58
59#ifndef LONGBITS
60# define LONGBITS (sizeof (long) * BITSPERBYTE)
61#endif
62
63#ifndef bcopy
64# define bcopy(S, D, N) memcpy ((D), (S), (N))
65#endif
66
67extern void *xmalloc PARAMS ((size_t __n));
68extern void *xcalloc PARAMS ((size_t __n, size_t __m));
69
70typedef struct hash_entry
71{
72  unsigned long used;
73  const void *key;
74  size_t keylen;
75  void *data;
76  struct hash_entry *next;
77}
78hash_entry;
79
80/* Prototypes for local functions.  */
81static void insert_entry_2 PARAMS ((hash_table *htab,
82                                    const void *key, size_t keylen,
83                                    unsigned long int hval, size_t idx,
84                                    void *data));
85static size_t lookup PARAMS ((hash_table *htab,
86                              const void *key, size_t keylen,
87                              unsigned long int hval));
88static size_t lookup_2 PARAMS ((hash_table *htab,
89                                const void *key, size_t keylen,
90                                unsigned long int hval));
91static unsigned long compute_hashval PARAMS ((const void *key, size_t keylen));
92static int is_prime PARAMS ((unsigned long int candidate));
93
94
95int
96init_hash (htab, init_size)
97     hash_table *htab;
98     unsigned long int init_size;
99{
100  /* We need the size to be a prime.  */
101  init_size = next_prime (init_size);
102
103  /* Initialize the data structure.  */
104  htab->size = init_size;
105  htab->filled = 0;
106  htab->first = NULL;
107  htab->table = (void *) xcalloc (init_size + 1, sizeof (hash_entry));
108  if (htab->table == NULL)
109    return -1;
110
111  obstack_init (&htab->mem_pool);
112
113  return 0;
114}
115
116
117int
118delete_hash (htab)
119     hash_table *htab;
120{
121  free (htab->table);
122  obstack_free (&htab->mem_pool, NULL);
123  return 0;
124}
125
126
127int
128insert_entry (htab, key, keylen, data)
129     hash_table *htab;
130     const void *key;
131     size_t keylen;
132     void *data;
133{
134  unsigned long int hval = compute_hashval (key, keylen);
135  hash_entry *table = (hash_entry *) htab->table;
136  size_t idx = lookup (htab, key, keylen, hval);
137
138  if (table[idx].used)
139    /* We don't want to overwrite the old value.  */
140    return -1;
141  else
142    {
143      /* An empty bucket has been found.  */
144      insert_entry_2 (htab, obstack_copy (&htab->mem_pool, key, keylen),
145                      keylen, hval, idx, data);
146      return 0;
147    }
148}
149
150static void
151insert_entry_2 (htab, key, keylen, hval, idx, data)
152     hash_table *htab;
153     const void *key;
154     size_t keylen;
155     unsigned long int hval;
156     size_t idx;
157     void *data;
158{
159  hash_entry *table = (hash_entry *) htab->table;
160
161  table[idx].used = hval;
162  table[idx].key = key;
163  table[idx].keylen = keylen;
164  table[idx].data = data;
165
166      /* List the new value in the list.  */
167  if ((hash_entry *) htab->first == NULL)
168    {
169      table[idx].next = &table[idx];
170      *(hash_entry **) &htab->first = &table[idx];
171    }
172  else
173    {
174      table[idx].next = ((hash_entry *) htab->first)->next;
175      ((hash_entry *) htab->first)->next = &table[idx];
176      *(hash_entry **) &htab->first = &table[idx];
177    }
178
179  ++htab->filled;
180  if (100 * htab->filled > 90 * htab->size)
181    {
182      /* Table is filled more than 90%.  Resize the table.  */
183      unsigned long int old_size = htab->size;
184
185      htab->size = next_prime (htab->size * 2);
186      htab->filled = 0;
187      htab->first = NULL;
188      htab->table = (void *) xcalloc (1 + htab->size, sizeof (hash_entry));
189
190      for (idx = 1; idx <= old_size; ++idx)
191        if (table[idx].used)
192          insert_entry_2 (htab, table[idx].key, table[idx].keylen,
193                          table[idx].used,
194                          lookup_2 (htab, table[idx].key, table[idx].keylen,
195                                    table[idx].used),
196                          table[idx].data);
197
198      free (table);
199    }
200}
201
202
203int
204find_entry (htab, key, keylen, result)
205     hash_table *htab;
206     const void *key;
207     size_t keylen;
208     void **result;
209{
210  hash_entry *table = (hash_entry *) htab->table;
211  size_t idx = lookup (htab, key, keylen, compute_hashval (key, keylen));
212
213  if (table[idx].used == 0)
214    return -1;
215
216  *result = table[idx].data;
217  return 0;
218}
219
220
221int
222iterate_table (htab, ptr, key, keylen, data)
223     hash_table *htab;
224     void **ptr;
225     const void **key;
226     size_t *keylen;
227     void **data;
228{
229  if (*ptr == NULL)
230    {
231      if (htab->first == NULL)
232        return -1;
233      *ptr = (void *) ((hash_entry *) htab->first)->next;
234    }
235  else
236    {
237      if (*ptr == htab->first)
238        return -1;
239      *ptr = (void *) (((hash_entry *) *ptr)->next);
240    }
241
242  *key = ((hash_entry *) *ptr)->key;
243  *keylen = ((hash_entry *) *ptr)->keylen;
244  *data = ((hash_entry *) *ptr)->data;
245  return 0;
246}
247
248
249static size_t
250lookup (htab, key, keylen, hval)
251     hash_table *htab;
252     const void *key;
253     size_t keylen;
254     unsigned long hval;
255{
256  unsigned long hash;
257  size_t idx;
258  hash_entry *table = (hash_entry *) htab->table;
259
260  /* First hash function: simply take the modul but prevent zero.  */
261  hash = 1 + hval % htab->size;
262
263  idx = hash;
264
265  if (table[idx].used)
266    {
267      if (table[idx].used == hval && table[idx].keylen == keylen
268          && memcmp (key, table[idx].key, keylen) == 0)
269        return idx;
270
271      /* Second hash function as suggested in [Knuth].  */
272      hash = 1 + hval % (htab->size - 2);
273
274      do
275        {
276          if (idx <= hash)
277            idx = htab->size + idx - hash;
278          else
279            idx -= hash;
280
281          /* If entry is found use it.  */
282          if (table[idx].used == hval && table[idx].keylen == keylen
283              && memcmp (key, table[idx].key, keylen) == 0)
284            return idx;
285        }
286      while (table[idx].used);
287    }
288  return idx;
289}
290
291
292/* References:
293   [Aho,Sethi,Ullman] Compilers: Principles, Techniques and Tools, 1986
294   [Knuth]            The Art of Computer Programming, part3 (6.4) */
295
296static size_t
297lookup_2 (htab, key, keylen, hval)
298     hash_table *htab;
299     const void *key;
300     size_t keylen;
301     unsigned long int hval;
302{
303  unsigned long int hash;
304  size_t idx;
305  hash_entry *table = (hash_entry *) htab->table;
306
307  /* First hash function: simply take the modul but prevent zero.  */
308  hash = 1 + hval % htab->size;
309
310  idx = hash;
311
312  if (table[idx].used)
313    {
314      if (table[idx].used == hval && table[idx].keylen == keylen
315          && memcmp (table[idx].key, key, keylen) == 0)
316        return idx;
317
318      /* Second hash function as suggested in [Knuth].  */
319      hash = 1 + hval % (htab->size - 2);
320
321      do
322        {
323          if (idx <= hash)
324            idx = htab->size + idx - hash;
325          else
326            idx -= hash;
327
328          /* If entry is found use it.  */
329          if (table[idx].used == hval && table[idx].keylen == keylen
330              && memcmp (table[idx].key, key, keylen) == 0)
331            return idx;
332        }
333      while (table[idx].used);
334    }
335  return idx;
336}
337
338
339static unsigned long
340compute_hashval (key, keylen)
341     const void *key;
342     size_t keylen;
343{
344  size_t cnt;
345  unsigned long int hval, g;
346
347  /* Compute the hash value for the given string.  The algorithm
348     is taken from [Aho,Sethi,Ullman].  */
349  cnt = 0;
350  hval = keylen;
351  while (cnt < keylen)
352    {
353      hval <<= 4;
354      hval += ((char *) key)[cnt++];
355      g = hval & ((unsigned long) 0xf << (LONGBITS - 4));
356      if (g != 0)
357        {
358          hval ^= g >> (LONGBITS - 8);
359          hval ^= g;
360        }
361    }
362  return hval != 0 ? hval : ~((unsigned long) 0);
363}
364
365
366unsigned long
367next_prime (seed)
368     unsigned long int seed;
369{
370  /* Make it definitely odd.  */
371  seed |= 1;
372
373  while (!is_prime (seed))
374    seed += 2;
375
376  return seed;
377}
378
379
380static int
381is_prime (candidate)
382     unsigned long int candidate;
383{
384  /* No even number and none less than 10 will be passed here.  */
385  unsigned long int divn = 3;
386  unsigned long int sq = divn * divn;
387
388  while (sq < candidate && candidate % divn != 0)
389    {
390      ++divn;
391      sq += 4 * divn;
392      ++divn;
393    }
394
395  return candidate % divn != 0;
396}
Note: See TracBrowser for help on using the repository browser.