Lists

The Eina_List is a double-linked list that can store data of any type as void pointers. It provides a set of functions to create and manipulate the list to avoid the access to the struct's fields, similar to a self-made double-link list.

In addition to the previous and next node and its data, the Eina_List nodes keep a reference to an accounting structure. The accounting structure is used to improve the performance of some functions. The structure is private and must not be modified.

In an Eina_List, everything is a "list": the list itself is a list where each node is a list as well.

Eina provides 2 list types: the classic (Eina_List) and inline (Eina_Inlist).

Creating and Destroying a List

To use an Eina_List, first declare the list with NULL as the default value:

[...]
int list()
{
   // Declaration of the Eina_List with NULL as default value;
   Eina_List *list = NULL;
[...]

NOTE: [...] in a Code Block indicates there will usually be code above and below the shown snippet but that it has been excluded for the sake of brevity. There is no need to type [...] into your program.

Then call the eina_list_append() function with the list and the data you want to append as parameters.

The list must be a pointer to the first element of the list (or NULL). The function returns a pointer to the list.

[...]
   // Creating the first element of the list
   list = eina_list_append(list, "watch");
 
   // Adding more elements
   list = eina_list_append(list, "phone");
   list = eina_list_append(list, "ivi");
   list = eina_list_append(list, "notebook");
[...]

When you no longer need the list, free it:

[...]
   // Free the Eina_List
   eina_list_free(list);
 
   return 0;
}
[...]

Modifying List Content

Adding Data to a List

To add data at the end of the list, use the eina_list_append() function. To add data at the top of the list, use eina_list_prepend(). The functions work in the same way, only adding the data to different places:

[...]
list = eina_list_prepend(list, "set-top box");
[...]

To insert data into the list after a specified data, use the eina_list_append_relative() function. As the last parameter, define the element after which the data is added. For example, to append data after the "phone" element:

[...]
list = eina_list_append_relative(list, "single-board computer", "phone");
[...]

To add a new entry before a specified data, use eina_list_prepend_relative(). This function is similar to eina_list_append_relative():

[...]
list = eina_list_prepend_relative(list, "ultrabook", "ivi");
[...]

To append a list node to a linked list after a specified element use the eina_list_append_relative_list() function. To prepend a list node to a linked list before a specified member, use Eina_List * eina_list_prepend_relative_list().

Setting Data in a List Element

To do this use the eina_list_data_set() function. Pass the list (node) as the first argument and the data to set as the second.

The following example also shows the usage of the eina_list_last() function, which returns the last element of an Eina_List:

[...]
// Setting new data for the last element
eina_list_data_set(eina_list_last(list), eina_stringshare_add("Boris"));
[...]

Removing a Node from the List

Use the eina_list_remove() function. This function removes the first instance of the specified data from the given list.

[...]
list = eina_list_remove(list, "ultrabook");
[...]

You can also remove a list (node) from a list using the eina_list_remove_list() function. Pass the list you want to delete an element from and a 'list' (node) you want to delete:

[...]
Eina_List *app_list = NULL;
Eina_List *to_remove = NULL;
 
// Adding some elements to the list (using stringshares)
app_list = eina_list_append(app_list, eina_stringshare_add("enna"));
app_list = eina_list_append(app_list, eina_stringshare_add("ebird"));
app_list = eina_list_append(app_list, eina_stringshare_add("calaos"));
app_list = eina_list_append(app_list, eina_stringshare_add("rage"));
app_list = eina_list_append(app_list, eina_stringshare_add("terminology"));
app_list = eina_list_append(app_list, eina_stringshare_add("enlightenment"));
app_list = eina_list_append(app_list, eina_stringshare_add("eyelight"));
app_list = eina_list_append(app_list, eina_stringshare_add("ephoto"));
 
// Finding the "list" to remove
to_remove = eina_list_data_find_list(list, eina_string_share_add("enlightenment"));
 
list = eina_list_remove_list(list, to_remove);
[...]

Moving Elements in a List

You can use various function such as eina_list_promote_list() to push an element to the top of a list or eina_list_demote_list() to move an element to the end. The second parameter represents the list (node) you want to move. Use the functions in the same way as eina_list_remove_list():

[...]
list = eina_list_promote_list(list, eina_list_data_find_list(list, "ivi"));
[...]

Reversing Elements in a List

Use the eina_list_reverse() function. To obtain a reversed copy of the list while keeping the initial list unchanged, useeina_list_reverse_clone():

[...]
Eina_List *rev_copy;
 
app_list = eina_list_reverse(app_list);
rev_copy = eina_list_reverse_clone(app_list);
[...]

Sorting a List

Use the eina_list_sort() function. This function takes a list that needs sorting, the maximum number of elements to sort and a callback function that compares data. To sort all list elements set the maximum number of elements to 0:

[...]
int sort_cb(const void *d1, const void *d2)
{
   const char *txt = d1;
   const char *txt2 = d2;
   if(!txt) return(1);
   if(!txt2) return(-1);
 
   return(strcmp(txt, txt2));
}
 
extern Eina_List *list;
list = eina_list_sort(list, 0, sort_cb);
[...]

Merging Two Lists into One

Use the eina_list_merge() function. The eina_list_sorted_merge() function merges 2 sorted lists according to the ordering function that you pass as the last argument, for instance:

[...]
int sort_cb(void *d1, void *d2)
{
   const char *txt = NULL;
   const char *txt2 = NULL;
   if(!d1) return(1);
   if(!d2) return(-1);
 
   return(strcmp((const char*)d1, (const char*)d2));
}
 
Eina_List *sorted1;
Eina_List *sorted2;
Eina_List *newlist;
 
// Insert some values and sort your lists
 
// Simply merge 2 lists without any process
newlist = eina_list_merge(sorted1, sorted2);
 
newlist = eina_list_sorted_merge(sorted1, sorted2, sort_cb);
[...]

Splitting a List

Use the eina_list_split_list() function. The first parameter is the list to split and the second parameter is the list (element) after which the list is to be split. The last parameter is the head of the second list.

[...]
// Original list (left list)
Eina_List *list = NULL;
 
// New list (right list)
Eina_List *other_list = NULL;
 
// Eina_List (element)
Eina_List *l;
 
list = eina_list_append(list, "super tux");
list = eina_list_append(list, "frozen bubble");
list = eina_list_append(list, "lincity-ng");
 
// Sorting the list (just for fun)
list = eina_list_sort(list, 0, cmp_func);
 
// Looking for the 'split' element
l = eina_list_search_sorted_list(list, cmp_func, "frozen bubble");
 
// Splitting the list
list = eina_list_split_list(list, l, &other_list);
[...]

Copying a List

Use the eina_list_clone() function. The function copies all the elements in the list in the exact same order:

[...]
Eina_List *app_list_copy;
 
app_list_copy = eina_list_clone(app_list);
[...]

Accessing List Data

Finding Data in your List

Use the eina_list_data_find() function. Pass the list containing your data as the first parameter and the data you are looking for as the last one. The function returns the found element's data pointer if found, NULL otherwise.

The eina_list_data_find() function searches the list from the beginning to the end for the first element's data pointer that coincides with the search term. If it is found, it returns the the data, otherwise it return NULL. The function only compares pointers, which is why using Eina_Stringshare is very useful with lists, because it always returns the same pointer for the same string:

[...]
Eina_List *app_list = NULL;
const char *res_str;
 
// Adding some elements to the list (using stringshares)
app_list = eina_list_append(app_list, eina_stringshare_add("enna"));
app_list = eina_list_append(app_list, eina_stringshare_add("ebird"));
app_list = eina_list_append(app_list, eina_stringshare_add("calaos"));
app_list = eina_list_append(app_list, eina_stringshare_add("rage"));
app_list = eina_list_append(app_list, eina_stringshare_add("terminology"));
app_list = eina_list_append(app_list, eina_stringshare_add("enlightenment"));
app_list = eina_list_append(app_list, eina_stringshare_add("eyelight"));
app_list = eina_list_append(app_list, eina_stringshare_add("ephoto"));
 
// Finding the data
res_str = eina_list_data_find(list, eina_string_share_add("enlightenment"));
if (res_str #### eina_stringshare_add("enlightenment"))
   printf("Data is present");
else
   printf("Data not present");
[...]

The above example returns "Data is present".

The eina_list_data_find_list() function does the same thing as eina_list_data_find() but returns an Eina_List. For an example, see the eina_list_remove_list() function.

You can access the data or a list (node) of an Eina_List using eina_list_nth() and eina_list_nth_list(). The first function returns a pointer to the data of the nth element and the second a pointer to the list. To access the data of the 3rd element of an Eina_List try:

[...]
const char *res;
Eina_List *res_lst;
 
res = eina_list_nth(app_list, 2);
res_lst = eina_list_nth_list(app_list, 2);
[...]

The res variable contains the pointer to the string "calaos". The res_lst variable is the list containing "calaos".

Searching for Data in a List

Select your function based on whether the list is sorted or unsorted.

To search in an unsorted list, use the eina_list_search_unsorted() function: The first parameter is the list. The second parameter is a callback function for comparison. The last parameter is the data you are looking for.

The eina_list_search_unsorted_list() function does the same but returns an "Eina_List".

The following example shows 2 searches using both the eina_list_search_unsorted() and eina_list_search_unsorted_list() functions:

[...]
int search_list()
{
   // Declaring the list
   Eina_List *list = NULL;
   Eina_List *l;
   // Little trick to use strcmp as Eina_Compare_Cb
   Eina_Compare_Cb cmp_func = (Eina_Compare_Cb)strcmp;
 
   void *data;
   int cmp_result;
 
   list = eina_list_append(list, "debian");
   list = eina_list_append(list, "archlinux");
   list = eina_list_append(list, "centos");
 
   data = eina_list_search_unsorted(list, cmp_func, "archlinux");
   l = eina_list_search_unsorted_list(list, cmp_func, "archlinux");
   if (l->data != data)
     {
        eina_list_free(list);
 
        return 1;
     }
 
   eina_list_free(list);
 
   return 0;
}
[...]

To search in sorted lists use the functions eina_list_search_sorted_list() and eina_list_search_sorted(). These work in a similar way to eina_list_search_unsorted().

Retrieving Data from a List Element

Use the eina_list_data_get() function, which returns the data contained in the given list.

The following example uses the eina_list_next() function to move through the list in a statement:

[...]
int list_data_set()
{
   // Declaring the list
   Eina_List *list = NULL;
   // Eina_List in which to place the elements or lists
   Eina_List *l;
 
   void *list_data;
 
   list = eina_list_append(list, eina_stringshare_add("Bertrand"));
   list = eina_list_append(list, eina_stringshare_add("Cedric"));
   list = eina_list_append(list, eina_stringshare_add("Nicolas"));
   list = eina_list_append(list, eina_stringshare_add("Vincent"));
   list = eina_list_append(list, eina_stringshare_add("Raoul"));
   list = eina_list_append(list, eina_stringshare_add("Fabien"));
   list = eina_list_append(list, eina_stringshare_add("Philippe"));
   list = eina_list_append(list, eina_stringshare_add("billiob"));
 
   for(l = list; l; l = eina_list_next(l))
      // Printing the data returned by eina_list_data_get
      printf("%s\n", (char*)eina_list_data_get(l));
 
   EINA_LIST_FREE(list, list_data)
      eina_stringshare_del(list_data);
 
   return 0;
}
[...]

Moving within a List

Use the eina_list_last(), eina_list_next() or eina_list_prev() functions to move to the last, next, or previous element in a list.

The following example moves backwards starting from the end of the list:

[...]
for(l = eina_list_last(list); l; l = eina_list_prev(l))
   printf("%s\n", (char*)eina_list_data_get(l));
[...]

Counting the Number of List Elements

Use the eina_list_count() function. This returns the number of elements in a list:

[...]
printf("List size: %d\n", eina_list_count(list));
[...]

Iterating through a List

There are several iterators you can use. To iterate over a list from the beginning to the end use the EINA_LIST_FOREACH macro. In this macro the first parameter is the list over which you want to iterate, the second parameter is an Eina_List * to hold the current list (node). The last parameter receives the current data during the run.

The following example prints the data of each list (node) of the list:

[...]
Eina_List *list = NULL;
Eina_List *l;
void *list_data;
 
list = eina_list_append(list, "ls");
list = eina_list_append(list, "top");
list = eina_list_append(list, "rmdir");
list = eina_list_append(list, "uname");
 
EINA_LIST_FOREACH(list, l, list_data)
   printf("%s\n", (char*)list_data);
 
eina_list_free(list);
[...]

To iterate from the last element to the first, use the EINA_LIST_REVERSE_FOREACH macro. It works similarly to EINA_LIST_FOREACH().

To iterate over a list from the beginning to the end you can also use the EINA_LIST_FOREACH_SAFE macro. It is so-named as it stores the next list (node), so you can safely remove the current list (node) and continue the iteration:

[...]
Eina_List *list;
Eina_List *l;
Eina_List *l_next;
char *data;
 
list = eina_list_append(list, "enlightenment");
list = eina_list_append(list, "enlightenment");
list = eina_list_append(list, "enlightenment");
list = eina_list_append(list, "enlightenment");
 
// Using EINA_LIST_FOREACH_SAFE to free the elements that match "enlightenment"
 
EINA_LIST_FOREACH_SAFE(list, l, l_next, data)
   if (strcmp(data, "enlightenment") #### 0)
     {
        free(data);
        list = eina_list_remove_list(list, l);
     }
[...]

To remove each list element while still having access to the node's data use the EINA_LIST_FREE macro. Pass the list and a pointer to hold the current data:

[...]
Eina_List *list;
char *data;
 
// List is filled
 
EINA_LIST_FREE(list, data)
   free(data);
[...]

Using an Inline List

The Eina_Inlist is a special data type designed to store nodes pointers in the same memory as data. This way the memory is less fragmented but operations such as sort and count are slower. The Eina_Inlist is designed for specific usage cases. If you're uncertain, use the regular Eina_List instead.

The Eina_Inlist nodes can be part of a regular Eina_List, simply added with the eina_list_append() or eina_list_prepend() functions.

To use the inline list, first define the structure of the data before creating the inline list:

[...]
struct my_struct
{
   EINA_INLIST;
   int a, b;
};
[...]

The structure is composed of 2 integers, the real data, and the EINA_INLIST type which is composed of 3 pointers defining the inline list structure:

  • Eina_Inlist * next: next node
  • Eina_Inlist * prev: previous node
  • Eina_Inlist * last: last node

To create the inlist nodes, allocate the memory and use the eina_inlist_append() function. The first parameter is the existing list head or NULL to create a new list. The following example passes NULL to create a new list.

The second parameter is the new list node, and it must not be NULL. You must use the EINA_INLIST_GET() macro to get the inlist object of the datastruct:

[...]
struct my_struct *d, *cur;
Eina_Inlist *list, *itr, *tmp;
 
d = malloc(sizeof(*d));
d->a = 1;
d->b = 10;
 
list = eina_inlist_append(NULL, EINA_INLIST_GET(d));
[...]

Repeat this operation for every new node:

[...]
d = malloc(sizeof(*d));
d->a = 2;
d->b = 20;
list = eina_inlist_append(list, EINA_INLIST_GET(d));
[...]

To add data to the inline list, place data at the end of the inline list with the eina_inlist_prepend() function:

[...]
d = malloc(sizeof(*d));
d->a = 3;
d->b = 30;
list = eina_inlist_prepend(list, EINA_INLIST_GET(d));
[...]

Add a node before or after a given node with the eina_inlist_prepend_relative() and eina_inlist_append_relative() functions. In both functions, the first parameter is the target list, the second is the element you want to add and the last is the reference element to place data after (in this case). As for a regular Eina_List, everything is a list, so the last parameter is an Eina_Inlist typed variable.

[...]
d = malloc(sizeof(*d));
d->a = 4;
d->b = 40;
list = eina_inlist_append_relative(list, EINA_INLIST_GET(d), list);
[...]

To sort and iterate an inline list, find and move list elements and to perform other inline list operations, see the [Inline List API](PAGE DOES NOT EXIST).

When the inline list is no longer needed destroy it by looping over the list to free each EINA_INLIST structure and the data using the allocated memory. Use eina_inlist_remove() on each node.

In the following example, the EINA_INLIST_CONTAINER_GET() macro returns the container object of an inlist (the EINA_INLIST of my_struct), the list element is removed and the allocated memory of the container "object" is freed:

[...]
while (list)
  {
     struct my_struct *aux = EINA_INLIST_CONTAINER_GET(list, struct my_struct);
 
     // Remove the current list element
     list = eina_inlist_remove(list, list);
     free(aux);
  }
[...]

Further Reading

List API
A reference for the List API.
List Example
An example of List API usage.