Exemple #1
0
void
hash_table_put (struct hash_table *ht, const void *key, void *value)
{
  struct mapping *mappings = ht->mappings;
  int size = ht->size;
  int (*equals) (const void *, const void *) = ht->test_function;

  struct mapping *mp = mappings + HASH_POSITION (ht, key);

  LOOP_NON_EMPTY (mp, mappings, size)
    if (equals (key, mp->key))
      {
	mp->key   = (void *)key; /* const? */
	mp->value = value;
	return;
      }

  ++ht->count;
  mp->key   = (void *)key;	/* const? */
  mp->value = value;

  if (ht->count > ht->resize_threshold)
    /* When table is 75% full, regrow it. */
    grow_hash_table (ht);
}
Exemple #2
0
static void
grow_hash_table (struct hash_table *ht)
{
  struct mapping *old_mappings = ht->mappings;
  struct mapping *old_end      = ht->mappings + ht->size;
  struct mapping *mp, *mappings;
  int newsize;

  newsize = prime_size (ht->size * 2);
#if 0
  printf ("growing from %d to %d\n", ht->size, newsize);
#endif

  ht->size = newsize;
  ht->resize_threshold = newsize * 3 / 4;

  mappings = xmalloc (ht->size * sizeof (struct mapping));
  memset (mappings, '\0', ht->size * sizeof (struct mapping));
  ht->mappings = mappings;

  for (mp = old_mappings; mp < old_end; mp++)
    if (!EMPTY_MAPPING_P (mp))
      {
	struct mapping *new_mp = mappings + HASH_POSITION (ht, mp->key);
	/* We don't need to call test function and worry about
	   collisions because all the keys come from the hash table
	   and are therefore guaranteed to be unique.  */
	LOOP_NON_EMPTY (new_mp, mappings, newsize)
	  ;
	*new_mp = *mp;
      }

  xfree (old_mappings);
}
Exemple #3
0
static inline struct mapping *
find_mapping (struct hash_table *ht, const void *key)
{
  struct mapping *mappings = ht->mappings;
  int size = ht->size;
  struct mapping *mp = mappings + HASH_POSITION (ht, key);
  int (*equals) (const void *, const void *) = ht->test_function;

  LOOP_NON_EMPTY (mp, mappings, size)
    if (equals (key, mp->key))
      return mp;
  return NULL;
}
Exemple #4
0
static inline struct cell *
find_cell (const struct hash_table *ht, const void *key)
{
  struct cell *cells = ht->cells;
  int size = ht->size;
  struct cell *c = cells + HASH_POSITION (key, ht->hash_function, size);
  testfun_t equals = ht->test_function;

  FOREACH_OCCUPIED_ADJACENT (c, cells, size)
    if (equals (key, c->key))
      break;
  return c;
}
Exemple #5
0
int
hash_table_remove (struct hash_table *ht, const void *key)
{
  struct cell *c = find_cell (ht, key);
  if (!CELL_OCCUPIED (c))
    return 0;
  else
    {
      int size = ht->size;
      struct cell *cells = ht->cells;
      hashfun_t hasher = ht->hash_function;

      CLEAR_CELL (c);
      --ht->count;

      /* Rehash all the entries following C.  The alternative
         approach is to mark the entry as deleted, i.e. create a
         "tombstone".  That speeds up removal, but leaves a lot of
         garbage and slows down hash_table_get and hash_table_put.  */

      c = NEXT_CELL (c, cells, size);
      FOREACH_OCCUPIED_ADJACENT (c, cells, size)
        {
          const void *key2 = c->key;
          struct cell *c_new;

          /* Find the new location for the key. */
          c_new = cells + HASH_POSITION (key2, hasher, size);
          FOREACH_OCCUPIED_ADJACENT (c_new, cells, size)
            if (key2 == c_new->key)
              /* The cell C (key2) is already where we want it (in
                 C_NEW's "chain" of keys.)  */
              goto next_rehash;

          *c_new = *c;
          CLEAR_CELL (c);

        next_rehash:
          ;
        }
      return 1;
    }
}
Exemple #6
0
int
hash_table_remove (struct hash_table *ht, const void *key)
{
  struct mapping *mp = find_mapping (ht, key);
  if (!mp)
    return 0;
  else
    {
      int size = ht->size;
      struct mapping *mappings = ht->mappings;

      mp->key = NULL;
      --ht->count;

      /* Rehash all the entries following MP.  The alternative
	 approach is to mark the entry as deleted, i.e. create a
	 "tombstone".  That makes remove faster, but leaves a lot of
	 garbage and slows down hash_table_get and hash_table_put.  */

      mp = NEXT_MAPPING (mp, mappings, size);
      LOOP_NON_EMPTY (mp, mappings, size)
	{
	  const void *key2 = mp->key;
	  struct mapping *mp_new = mappings + HASH_POSITION (ht, key2);

	  /* Find the new location for the key. */

	  LOOP_NON_EMPTY (mp_new, mappings, size)
	    if (key2 == mp_new->key)
	      /* The mapping MP (key2) is already where we want it (in
		 MP_NEW's "chain" of keys.)  */
	      goto next_rehash;

	  *mp_new = *mp;
	  mp->key = NULL;

	next_rehash:
	  ;
	}
      return 1;
    }
}
Exemple #7
0
static void
grow_hash_table (struct hash_table *ht)
{
  hashfun_t hasher = ht->hash_function;
  struct cell *old_cells = ht->cells;
  struct cell *old_end   = ht->cells + ht->size;
  struct cell *c, *cells;
  int newsize;

  newsize = prime_size (ht->size * HASH_RESIZE_FACTOR, &ht->prime_offset);
#if 0
  printf ("growing from %d to %d; fullness %.2f%% to %.2f%%\n",
          ht->size, newsize,
          100.0 * ht->count / ht->size,
          100.0 * ht->count / newsize);
#endif

  ht->size = newsize;
  ht->resize_threshold = newsize * HASH_MAX_FULLNESS;

  cells = xnew_array (struct cell, newsize);
  memset (cells, INVALID_PTR_CHAR, newsize * sizeof (struct cell));
  ht->cells = cells;

  for (c = old_cells; c < old_end; c++)
    if (CELL_OCCUPIED (c))
      {
        struct cell *new_c;
        /* We don't need to test for uniqueness of keys because they
           come from the hash table and are therefore known to be
           unique.  */
        new_c = cells + HASH_POSITION (c->key, hasher, newsize);
        FOREACH_OCCUPIED_ADJACENT (new_c, cells, newsize)
          ;
        *new_c = *c;
      }

  xfree (old_cells);
}