Currently, whenever the addition of an entry gets 80% of buckets to be
non-empty, this package automatically doubles the number of buckets. */
-\f
+
/* Information and lookup. */
/* The following few functions provide information about the overall hash
unsigned int max_bucket_length = 0;
for (bucket = table->bucket; bucket < table->bucket_limit; bucket++)
- if (bucket->data)
- {
- struct hash_entry *cursor = bucket;
- unsigned int bucket_length = 1;
+ {
+ if (bucket->data)
+ {
+ struct hash_entry *cursor = bucket;
+ unsigned int bucket_length = 1;
- while (cursor = cursor->next, cursor)
- bucket_length++;
+ while (cursor = cursor->next, cursor)
+ bucket_length++;
- if (bucket_length > max_bucket_length)
- max_bucket_length = bucket_length;
- }
+ if (bucket_length > max_bucket_length)
+ max_bucket_length = bucket_length;
+ }
+ }
return max_bucket_length;
}
unsigned int n_entries = 0;
for (bucket = table->bucket; bucket < table->bucket_limit; bucket++)
- if (bucket->data)
- {
- struct hash_entry *cursor = bucket;
-
- /* Count bucket head. */
- n_buckets_used++;
- n_entries++;
+ {
+ if (bucket->data)
+ {
+ struct hash_entry *cursor = bucket;
- /* Count bucket overflow. */
- while (cursor = cursor->next, cursor)
+ /* Count bucket head. */
+ n_buckets_used++;
n_entries++;
- }
+
+ /* Count bucket overflow. */
+ while (cursor = cursor->next, cursor)
+ n_entries++;
+ }
+ }
if (n_buckets_used == table->n_buckets_used && n_entries == table->n_entries)
return true;
return NULL;
}
-\f
+
/* Walking. */
/* The functions in this page traverse the hash table and process the
struct hash_entry *cursor;
for (bucket = table->bucket; bucket < table->bucket_limit; bucket++)
- if (bucket->data)
- for (cursor = bucket; cursor; cursor = cursor->next)
+ {
+ if (bucket->data)
{
- if (counter >= buffer_size)
- return counter;
- buffer[counter++] = cursor->data;
+ for (cursor = bucket; cursor; cursor = cursor->next)
+ {
+ if (counter >= buffer_size)
+ return counter;
+ buffer[counter++] = cursor->data;
+ }
}
+ }
return counter;
}
struct hash_entry *cursor;
for (bucket = table->bucket; bucket < table->bucket_limit; bucket++)
- if (bucket->data)
- for (cursor = bucket; cursor; cursor = cursor->next)
+ {
+ if (bucket->data)
{
- if (!(*processor) (cursor->data, processor_data))
- return counter;
- counter++;
+ for (cursor = bucket; cursor; cursor = cursor->next)
+ {
+ if (!(*processor) (cursor->data, processor_data))
+ return counter;
+ counter++;
+ }
}
+ }
return counter;
}
-\f
+
/* Allocation and clean-up. */
/* Return a hash index for a NUL-terminated STRING between 0 and N_BUCKETS-1.
struct hash_entry *cursor;
for (bucket = table->bucket; bucket < table->bucket_limit; bucket++)
- if (bucket->data)
- {
- /* Free the bucket overflow. */
- for (cursor = bucket->next; cursor; cursor = cursor->next)
- {
- if (table->data_freer)
- (*table->data_freer) (cursor->data);
- cursor->data = NULL;
-
- /* Relinking is done one entry at a time, as it is to be expected
- that overflows are either rare or short. */
- cursor->next = table->free_entry_list;
- table->free_entry_list = cursor;
- }
-
- /* Free the bucket head. */
- if (table->data_freer)
- (*table->data_freer) (bucket->data);
- bucket->data = NULL;
- bucket->next = NULL;
- }
+ {
+ if (bucket->data)
+ {
+ /* Free the bucket overflow. */
+ for (cursor = bucket->next; cursor; cursor = cursor->next)
+ {
+ if (table->data_freer)
+ (*table->data_freer) (cursor->data);
+ cursor->data = NULL;
+
+ /* Relinking is done one entry at a time, as it is to be expected
+ that overflows are either rare or short. */
+ cursor->next = table->free_entry_list;
+ table->free_entry_list = cursor;
+ }
+
+ /* Free the bucket head. */
+ if (table->data_freer)
+ (*table->data_freer) (bucket->data);
+ bucket->data = NULL;
+ bucket->next = NULL;
+ }
+ }
table->n_buckets_used = 0;
table->n_entries = 0;
/* Call the user data_freer function. */
if (table->data_freer && table->n_entries)
- for (bucket = table->bucket; bucket < table->bucket_limit; bucket++)
- if (bucket->data)
- for (cursor = bucket; cursor; cursor = cursor->next)
- (*table->data_freer) (cursor->data);
+ {
+ for (bucket = table->bucket; bucket < table->bucket_limit; bucket++)
+ {
+ if (bucket->data)
+ {
+ for (cursor = bucket; cursor; cursor = cursor->next)
+ {
+ (*table->data_freer) (cursor->data);
+ }
+ }
+ }
+ }
#if USE_OBSTACK
/* Free all bucket overflowed entries. */
for (bucket = table->bucket; bucket < table->bucket_limit; bucket++)
- for (cursor = bucket->next; cursor; cursor = next)
- {
- next = cursor->next;
- free (cursor);
- }
+ {
+ for (cursor = bucket->next; cursor; cursor = next)
+ {
+ next = cursor->next;
+ free (cursor);
+ }
+ }
/* Also reclaim the internal list of previously freed entries. */
for (cursor = table->free_entry_list; cursor; cursor = next)
free (table->bucket);
free (table);
}
-\f
+
/* Insertion and deletion. */
/* Get a new hash entry for a bucket overflow, possibly by reclying a
void *data = bucket->data;
if (delete)
- if (bucket->next)
- {
- struct hash_entry *next = bucket->next;
-
- /* Bump the first overflow entry into the bucket head, then save
- the previous first overflow entry for later recycling. */
- *bucket = *next;
- free_entry (table, next);
- }
- else
- bucket->data = NULL;
+ {
+ if (bucket->next)
+ {
+ struct hash_entry *next = bucket->next;
+
+ /* Bump the first overflow entry into the bucket head, then save
+ the previous first overflow entry for later recycling. */
+ *bucket = *next;
+ free_entry (table, next);
+ }
+ else
+ {
+ bucket->data = NULL;
+ }
+ }
return data;
}
/* Scan the bucket overflow. */
for (cursor = bucket; cursor->next; cursor = cursor->next)
- if ((*table->comparator) (entry, cursor->next->data))
- {
- void *data = cursor->next->data;
+ {
+ if ((*table->comparator) (entry, cursor->next->data))
+ {
+ void *data = cursor->next->data;
- if (delete)
- {
- struct hash_entry *next = cursor->next;
+ if (delete)
+ {
+ struct hash_entry *next = cursor->next;
- /* Unlink the entry to delete, then save the freed entry for later
- recycling. */
- cursor->next = next->next;
- free_entry (table, next);
- }
+ /* Unlink the entry to delete, then save the freed entry for later
+ recycling. */
+ cursor->next = next->next;
+ free_entry (table, next);
+ }
- return data;
- }
+ return data;
+ }
+ }
/* No entry found. */
return NULL;
new_table->free_entry_list = table->free_entry_list;
for (bucket = table->bucket; bucket < table->bucket_limit; bucket++)
- if (bucket->data)
- for (cursor = bucket; cursor; cursor = next)
+ {
+ if (bucket->data)
{
- void *data = cursor->data;
- struct hash_entry *new_bucket
- = new_table->bucket + new_table->hasher (data, new_n_buckets);
-
- assert (new_bucket < new_table->bucket_limit);
-
- /* Free overflow entries as soon as possible, moving them from the
- old hash table into the new one, as they may be needed now. */
- next = cursor->next;
- if (cursor != bucket)
- free_entry (new_table, cursor);
-
- /* Insert the entry into the new hash table. */
- if (new_bucket->data)
- {
- struct hash_entry *new_entry = allocate_entry (new_table);
-
- if (new_entry == NULL)
- return false;
-
- new_entry->data = data;
- new_entry->next = new_bucket->next;
- new_bucket->next = new_entry;
- }
- else
+ for (cursor = bucket; cursor; cursor = next)
{
- new_bucket->data = data;
- new_table->n_buckets_used++;
+ void *data = cursor->data;
+ struct hash_entry *new_bucket
+ = new_table->bucket + new_table->hasher (data, new_n_buckets);
+
+ assert (new_bucket < new_table->bucket_limit);
+
+ /* Free overflow entries as soon as possible, moving them from the
+ old hash table into the new one, as they may be needed now. */
+ next = cursor->next;
+ if (cursor != bucket)
+ free_entry (new_table, cursor);
+
+ /* Insert the entry into the new hash table. */
+ if (new_bucket->data)
+ {
+ struct hash_entry *new_entry = allocate_entry (new_table);
+
+ if (new_entry == NULL)
+ return false;
+
+ new_entry->data = data;
+ new_entry->next = new_bucket->next;
+ new_bucket->next = new_entry;
+ }
+ else
+ {
+ new_bucket->data = data;
+ new_table->n_buckets_used++;
+ }
}
}
+ }
free (table->bucket);
table->bucket = new_table->bucket;
return data;
}
-\f
+
/* Testing. */
#if TESTING