/* An expandable hash tables datatype.
- Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004
+ Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2009
Free Software Foundation, Inc.
Contributed by Vladimir Makarov (vmakarov@cygnus.com).
#ifdef HAVE_LIMITS_H
#include <limits.h>
#endif
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
#ifdef HAVE_STDINT_H
#include <stdint.h>
#endif
#define CHAR_BIT 8
#endif
-/* This macro defines reserved value for empty table entry. */
-
-#define EMPTY_ENTRY ((PTR) 0)
-
-/* This macro defines reserved value for table entry which contained
- a deleted element. */
-
-#define DELETED_ENTRY ((PTR) 1)
-
static unsigned int higher_prime_index (unsigned long);
static hashval_t htab_mod_1 (hashval_t, hashval_t, hashval_t, int);
static hashval_t htab_mod (hashval_t, htab_t);
static hashval_t
hash_pointer (const PTR p)
{
- return (hashval_t) ((long)p >> 3);
+ return (hashval_t) ((intptr_t)p >> 3);
}
/* Returns non-zero if P1 and P2 are equal. */
/* This function creates table with length slightly longer than given
source length. Created hash table is initiated as empty (all the
- hash table entries are EMPTY_ENTRY). The function returns the
+ hash table entries are HTAB_EMPTY_ENTRY). The function returns the
created hash table, or NULL if memory allocation fails. */
htab_t
if (htab->del_f)
for (i = size - 1; i >= 0; i--)
- if (entries[i] != EMPTY_ENTRY && entries[i] != DELETED_ENTRY)
+ if (entries[i] != HTAB_EMPTY_ENTRY && entries[i] != HTAB_DELETED_ENTRY)
(*htab->del_f) (entries[i]);
if (htab->free_f != NULL)
if (htab->del_f)
for (i = size - 1; i >= 0; i--)
- if (entries[i] != EMPTY_ENTRY && entries[i] != DELETED_ENTRY)
+ if (entries[i] != HTAB_EMPTY_ENTRY && entries[i] != HTAB_DELETED_ENTRY)
(*htab->del_f) (entries[i]);
- memset (entries, 0, size * sizeof (PTR));
+ /* Instead of clearing megabyte, downsize the table. */
+ if (size > 1024*1024 / sizeof (PTR))
+ {
+ int nindex = higher_prime_index (1024 / sizeof (PTR));
+ int nsize = prime_tab[nindex].prime;
+
+ if (htab->free_f != NULL)
+ (*htab->free_f) (htab->entries);
+ else if (htab->free_with_arg_f != NULL)
+ (*htab->free_with_arg_f) (htab->alloc_arg, htab->entries);
+ if (htab->alloc_with_arg_f != NULL)
+ htab->entries = (PTR *) (*htab->alloc_with_arg_f) (htab->alloc_arg, nsize,
+ sizeof (PTR *));
+ else
+ htab->entries = (PTR *) (*htab->alloc_f) (nsize, sizeof (PTR *));
+ htab->size = nsize;
+ htab->size_prime_index = nindex;
+ }
+ else
+ memset (entries, 0, size * sizeof (PTR));
+ htab->n_deleted = 0;
+ htab->n_elements = 0;
}
/* Similar to htab_find_slot, but without several unwanted side effects:
PTR *slot = htab->entries + index;
hashval_t hash2;
- if (*slot == EMPTY_ENTRY)
+ if (*slot == HTAB_EMPTY_ENTRY)
return slot;
- else if (*slot == DELETED_ENTRY)
+ else if (*slot == HTAB_DELETED_ENTRY)
abort ();
hash2 = htab_mod_m2 (hash, htab);
index -= size;
slot = htab->entries + index;
- if (*slot == EMPTY_ENTRY)
+ if (*slot == HTAB_EMPTY_ENTRY)
return slot;
- else if (*slot == DELETED_ENTRY)
+ else if (*slot == HTAB_DELETED_ENTRY)
abort ();
}
}
{
PTR x = *p;
- if (x != EMPTY_ENTRY && x != DELETED_ENTRY)
+ if (x != HTAB_EMPTY_ENTRY && x != HTAB_DELETED_ENTRY)
{
PTR *q = find_empty_slot_for_expand (htab, (*htab->hash_f) (x));
index = htab_mod (hash, htab);
entry = htab->entries[index];
- if (entry == EMPTY_ENTRY
- || (entry != DELETED_ENTRY && (*htab->eq_f) (entry, element)))
+ if (entry == HTAB_EMPTY_ENTRY
+ || (entry != HTAB_DELETED_ENTRY && (*htab->eq_f) (entry, element)))
return entry;
hash2 = htab_mod_m2 (hash, htab);
index -= size;
entry = htab->entries[index];
- if (entry == EMPTY_ENTRY
- || (entry != DELETED_ENTRY && (*htab->eq_f) (entry, element)))
+ if (entry == HTAB_EMPTY_ENTRY
+ || (entry != HTAB_DELETED_ENTRY && (*htab->eq_f) (entry, element)))
return entry;
}
}
first_deleted_slot = NULL;
entry = htab->entries[index];
- if (entry == EMPTY_ENTRY)
+ if (entry == HTAB_EMPTY_ENTRY)
goto empty_entry;
- else if (entry == DELETED_ENTRY)
+ else if (entry == HTAB_DELETED_ENTRY)
first_deleted_slot = &htab->entries[index];
else if ((*htab->eq_f) (entry, element))
return &htab->entries[index];
index -= size;
entry = htab->entries[index];
- if (entry == EMPTY_ENTRY)
+ if (entry == HTAB_EMPTY_ENTRY)
goto empty_entry;
- else if (entry == DELETED_ENTRY)
+ else if (entry == HTAB_DELETED_ENTRY)
{
if (!first_deleted_slot)
first_deleted_slot = &htab->entries[index];
if (first_deleted_slot)
{
htab->n_deleted--;
- *first_deleted_slot = EMPTY_ENTRY;
+ *first_deleted_slot = HTAB_EMPTY_ENTRY;
return first_deleted_slot;
}
PTR *slot;
slot = htab_find_slot_with_hash (htab, element, hash, NO_INSERT);
- if (*slot == EMPTY_ENTRY)
+ if (*slot == HTAB_EMPTY_ENTRY)
return;
if (htab->del_f)
(*htab->del_f) (*slot);
- *slot = DELETED_ENTRY;
+ *slot = HTAB_DELETED_ENTRY;
htab->n_deleted++;
}
htab_clear_slot (htab_t htab, PTR *slot)
{
if (slot < htab->entries || slot >= htab->entries + htab_size (htab)
- || *slot == EMPTY_ENTRY || *slot == DELETED_ENTRY)
+ || *slot == HTAB_EMPTY_ENTRY || *slot == HTAB_DELETED_ENTRY)
abort ();
if (htab->del_f)
(*htab->del_f) (*slot);
- *slot = DELETED_ENTRY;
+ *slot = HTAB_DELETED_ENTRY;
htab->n_deleted++;
}
{
PTR *slot;
PTR *limit;
-
+
slot = htab->entries;
limit = slot + htab_size (htab);
{
PTR x = *slot;
- if (x != EMPTY_ENTRY && x != DELETED_ENTRY)
+ if (x != HTAB_EMPTY_ENTRY && x != HTAB_DELETED_ENTRY)
if (!(*callback) (slot, info))
break;
}
void
htab_traverse (htab_t htab, htab_trav callback, PTR info)
{
- if (htab_elements (htab) * 8 < htab_size (htab))
+ size_t size = htab_size (htab);
+ if (htab_elements (htab) * 8 < size && size > 32)
htab_expand (htab);
htab_traverse_noresize (htab, callback, info);