Eina_Hash in action

We are going to store some tuples into our table, that will map each name to a number. The cost to access a given number from the name should be very small, even with many entries in our table. This is the initial data:

struct _Phone_Entry {
const char *name; // Full name.
const char *number; // Phone number.
};
typedef struct _Phone_Entry Phone_Entry;
static Phone_Entry _start_entries[] = {
{ "Wolfgang Amadeus Mozart", "+01 23 456-78910" },
{ "Ludwig van Beethoven", "+12 34 567-89101" },
{ "Richard Georg Strauss", "+23 45 678-91012" },
{ "Heitor Villa-Lobos", "+34 56 789-10123" },
{ NULL, NULL }
}; // _start_entries

Before starting to play with the hash, let's write a callback that will be used to free the elements from it. Since we are just storing strduped strings, we just need to free them:

static void
_phone_entry_free_cb(void *data)
{
free(data);
}

We also need a callback to iterate over the elements of the list later, so we are defining it now:

static Eina_Bool
_phone_book_foreach_cb(const Eina_Hash *phone_book EINA_UNUSED, const void *key,
void *data, void *fdata EINA_UNUSED)
{
const char *name = key;
const char *number = data;
printf("%s: %s\n", name, number);
// Return EINA_FALSE to stop this callback from being called
return EINA_TRUE;
}
Eina_Hash
struct _Eina_Hash Eina_Hash
Type for a generic hash table.
Definition: eina_hash.h:285
EINA_TRUE
#define EINA_TRUE
boolean value TRUE (numerical value 1)
Definition: eina_types.h:539
Eina_Bool
unsigned char Eina_Bool
Type to mimic a boolean.
Definition: eina_types.h:527
EINA_UNUSED
#define EINA_UNUSED
Used to indicate that a function parameter is purposely unused.
Definition: eina_types.h:339

Now let's create our Eina_Hash using eina_hash_string_superfast_new :

eina_init();
phone_book = eina_hash_string_superfast_new(_phone_entry_free_cb);
eina_hash_string_superfast_new
EINA_API Eina_Hash * eina_hash_string_superfast_new(Eina_Free_Cb data_free_cb)
Creates a new hash table for use with strings.
Definition: eina_hash.c:790
eina_init
EINA_API int eina_init(void)
Initializes the Eina library.
Definition: eina_main.c:291

Now we add the keys and data to the hash using eina_hash_add . This means that the key is copied inside the table, together with the pointer to the data (phone numbers).

for (i = 0; _start_entries[i].name != NULL; i++)
{
eina_hash_add(phone_book, _start_entries[i].name,
strdup(_start_entries[i].number));
}
eina_hash_add
EINA_API Eina_Bool eina_hash_add(Eina_Hash *hash, const void *key, const void *data)
Adds an entry to the given hash table.
Definition: eina_hash.c:931

Some basic manipulations with the hash, like finding a value given a key, deleting an entry, modifying an entry are exemplified in the following lines. Notice that the eina_hash_modify function returns the old value stored in that entry, and it needs to be freed, while the eina_hash_del function already calls our free callback:

// Look for a specific entry and get its phone number
phone = eina_hash_find(phone_book, entry_name);
if (phone)
{
printf("Printing entry.\n");
printf("Name: %s\n", entry_name);
printf("Number: %s\n\n", phone);
}
// Delete this entry
r = eina_hash_del(phone_book, entry_name, NULL);
printf("Hash entry successfully deleted? %d\n\n", r);
// Modify the pointer data of an entry and free the old one
phone = eina_hash_modify(phone_book, "Richard Georg Strauss",
strdup("+23 45 111-11111"));
free(phone);
eina_hash_del
EINA_API Eina_Bool eina_hash_del(Eina_Hash *hash, const void *key, const void *data)
Removes the entry identified by a key or a data from the given hash table.
Definition: eina_hash.c:1030
eina_hash_modify
EINA_API void * eina_hash_modify(Eina_Hash *hash, const void *key, const void *data)
Modifies the entry pointer at the specified key and returns the previous entry.
Definition: eina_hash.c:1174
eina_hash_find
EINA_API void * eina_hash_find(const Eina_Hash *hash, const void *key)
Retrieves a specific entry in the given hash table.
Definition: eina_hash.c:1069

The eina_hash_set function can be used to set a key-value entry to the table if it doesn't exist, or to modify an existent entry. It returns the old entry if it was already set, and NULL otherwise. But since it will return NULL on error too, we need to check if an error has occurred:

// Modify or add an entry to the hash with eina_hash_set
// Let's first add a new entry
phone = eina_hash_set(phone_book, "Raul Seixas",
strdup("+55 01 234-56789"));
if (!phone)
{
printf("No previous phone found for Raul Seixas. ");
printf("Creating new entry.\n");
}
else
{
printf("Old phone for Raul Seixas was %s\n", phone);
free(phone);
}
printf("\n");
eina_hash_set
EINA_API void * eina_hash_set(Eina_Hash *hash, const void *key, const void *data)
Modifies the entry pointer at the specified key and returns the previous entry or adds the entry if n...
Definition: eina_hash.c:1121

There are different ways of iterate over the entries of a hash. Here we show two of them: using eina_hash_foreach and Eina_Iterator.

printf("List of phones:\n");
eina_hash_foreach(phone_book, _phone_book_foreach_cb, NULL);
printf("\n");
// Now iterate using an iterator
printf("List of phones:\n");
it = eina_hash_iterator_tuple_new(phone_book);
while (eina_iterator_next(it, &data))
{
Eina_Hash_Tuple *t = data;
const char *name = t->key;
const char *number = t->data;
printf("%s: %s\n", name, number);
}
eina_iterator_free(it); // Always free the iterator after its use
eina_hash_foreach
EINA_API void eina_hash_foreach(const Eina_Hash *hash, Eina_Hash_Foreach func, const void *fdata)
Calls a function on every member stored in the hash table.
Definition: eina_hash.c:1223
eina_hash_iterator_tuple_new
EINA_API Eina_Iterator * eina_hash_iterator_tuple_new(const Eina_Hash *hash)
Returned a new iterator associated with hash keys and data.
Definition: eina_hash.c:1299
eina_iterator_free
EINA_API void eina_iterator_free(Eina_Iterator *iterator)
Frees an iterator.
Definition: eina_iterator.c:98
eina_iterator_next
EINA_API Eina_Bool eina_iterator_next(Eina_Iterator *iterator, void **data)
Returns the value of the current element and go to the next one.
Definition: eina_iterator.c:118
_Eina_Hash_Tuple
Data for a hash table of key/value pairs.
Definition: eina_hash.h:298

It's also possible to change the key for a specific entry, without having to remove the entry from the table and adding it again:

eina_hash_move(phone_book, "Raul Seixas", "Alceu Valenca");
eina_hash_move
EINA_API Eina_Bool eina_hash_move(Eina_Hash *hash, const void *old_key, const void *new_key)
Changes the key of an entry in a hash without triggering the free callback.
Definition: eina_hash.c:1191

We can remove all the elements from the table without free the table itself:

// Empty the phone book, but don't destroy it
eina_hash_free_buckets(phone_book);
printf("There are %d items in the hash.\n\n",
eina_hash_population(phone_book));
eina_hash_free_buckets
EINA_API void eina_hash_free_buckets(Eina_Hash *hash)
Frees the given hash table buckets resources.
Definition: eina_hash.c:886
eina_hash_population
EINA_API int eina_hash_population(const Eina_Hash *hash)
Returns the number of entries in the given hash table.
Definition: eina_hash.c:858

Or free the the entire table with its content:

eina_hash_free(phone_book);
eina_hash_free
EINA_API void eina_hash_free(Eina_Hash *hash)
Frees the given hash table's resources.
Definition: eina_hash.c:868

The full code for this example can be seen here: Hash table in action