Arrays

An array is a data type which describes an ordered collection of values. Values are accessed by their index.

INDEX VALUE
0 value0
1 value1
2 value2
3 value3
4 value4
5 value5
6 value6
7 value7

Eina provides 2 array types: the classic array and an inline array.

Create and Destroy a Classic Array

The eina_array_new() function creates a new array. You can store strings or objects within it. The function returns either a new array or if memory allocation fails NULL.

The first parameter of the eina_array_new() function defines the size of the array allocation step. For example, if you set it to 4 the function returns an array of 4 elements. The next time you expand the array it increases by 4 elements. Unless you have pushed 4 elements inside it does not increase in size. Once you add the 5th element however it expands again into an array of 8 elements. The allocation step feature is very useful for optimizing performance and also reduces memory fragmentation by matching the size to array usage. If you set the step to 0 the function sets a default safe value.

Create an Array to Store Strings

First create the array:

[...]
 
// Strings to store in the array
const char* strings[] =
{
   "helo", "hera", "starbuck", "kat", "boomer",
   "hotdog", "longshot", "jammer", "crashdown", "hardball",
   "duck", "racetrack", "apolo", "husker", "freaker",
   "skulls", "bulldog", "flat top", "hammerhead", "gonzo"
};
// Declaring the array (type Eina_Array)
Eina_Array *array;
unsigned int i;
 
// Creating the array
array = eina_array_new(20);
 
// Inserting elements in the array
for (i = 0; i < 20; i++)
   eina_array_push(array, strdup(strings[i]));
 
[...]

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.

To change the allocation step use the function eina_array_step_set(). The first parameter is the array you want to change, the second parameter is the size of that specific array (retrieved with the sizeof() function). The final parameter is the new step size.

In this example the array step changes from 20 to 30:

[...]
eina_array_step_set(array, sizeof(*array), 30);
[...]

When you no longer require the array, use the eina_array_free() function to free it. This will first call the eina_array_flush() function and free the memory of the pointer. It does not free the memory allocated for the elements of the array. To do this use a while statement with the eina_array_pop function:

[...]
// Freeing the array elements
while (eina_array_count(array))
   free(eina_array_pop(array));
 
   // Freeing the array itself
eina_array_free(array);
[...]

Modify Classic Array Content

Set the Data of an Element

Use the eina_array_data_set() function to set the data of an element. The first parameter is the array. The second parameter is the index of the element you want to set and the final parameter is the data itself. You must first get the related pointer if you need to free it, as this function replaces the previously held data. Be careful as there is no array or index check. If the value is NULL or invalid the application may crash.

[...]
free(eina_array_data_get(array, 0));
eina_array_data_set(array, 0, strdup(strings[3]);
[...]

Add Elements to the End of an Array

Use the eina_array_push() function to add elements to the end of an array. The function returns EINA_TRUE on success and EINA_FALSE on failure. The first parameter is the array which will store the element. The second is the data you want to store. If you store strings, remember to allocate the necessary memory first. The following example uses the strdup function to duplicate the value contained in strings[]. This function allocates the memory of the returned string so you do not have to do it yourself:

[...]
for (i = 0; i < 20; i++)
   eina_array_push(array, strdup(strings[i]));
[...]

Remove the Last Element of an Array

Use the eina_array_pop() function to remove the last element. The function takes the array as a parameter. If the operation is successful it returns a pointer to the data of the removed element:

[...]
while (eina_array_count(array))
   free(eina_array_pop(array));
[...]

Rebuild an Array by Specifying the Data to be Kept

Use the eina_array_remove() function to rebuild an array. The first parameter is the array to be changed. The second is the function which selects the data to keep in the rebuilt array. The final parameter is the data to pass to the selector function, defined as the second parameter.

The selector function has to return an Eina_Bool EINA_TRUE if the element is to remain and EINA_FALSE if it has to be removed.

The following example shows how to remove all strings that are longer than 5 characters from an array :

[...]
// Selector function
Eina_Bool keep(void *data, void *gdata)
{
   if (strlen((const char*)data) <= 5)
      return EINA_TRUE;
 
   return EINA_FALSE;
}
 
int remove_array()
{
   Eina_Array *array;
   Eina_Array_Iterator iterator;
   const char *item;
   unsigned int i;
 
   // Creating and populating an array
 
   // Removing the undesired elements
   eina_array_remove(array, keep, NULL);
 
   // Flushing and freeing the array
 
   return 0;
}
[...]

Wipe all Data from an Array

Use the eina_array_flush() function. This function sets the count and total elements of an array to 0, and frees and sets its data elements to NULL. For performance reasons, there is no array check. If the value is NULL or invalid, the program can crash. The only parameter of this function is a pointer to the Eina_Array array you want to flush.

[...]
eina_array_flush(array);
[...]

Empty an Array Quickly

Use the eina_array_clean() function to empty an array. This function sets the elements count in the array to 0. It does not free any space so use it carefully. For performance reasons there is no array check. If the value is NULL or invalid the program may crash.

[...]
eina_array_clean(array);
[...]

Accessing Classic Array Data

Access Data in an Array

Use the eina_array_data_get() function with the array and the index of the element you want to access. The function returns a pointer to the data:

[...]
// Getting the data of the first element
char *mydata;
mydata = eina_array_data_get(array, 0);
[...]

Get the Number of Elements in an Array

Use the eina_array_count() function. The first parameter is a pointer to the array variable returned by the eina_array_new() function. The function returns the number of elements:

[...]
unsigned int nb_elm;
nb_elm = eina_array_count(array);
[...]

Iterate through an Array

You can use various methods:

Use the ITER_NEXT iterator

You can use the iterator by calling the macro EINA_ARRAY_ITER_NEXT(). It takes the array to iterate as the first parameter, a counter for the current index during the iteration and a variable of the same type as the item data and an Eina_Iterator. To use it declare an Eina_Iterator, an int counter, and a char * item if your array contains strings:

[...]
Eina_Array_Iterator iterator;
const char *item;
unsigned int i;
 
EINA_ARRAY_ITER_NEXT(array, i, item, iterator)
   printf("item #%d: %s\n", i, item);
[...]

Use the eina_array_foreach() Function

The first parameter is the array to iterate, the second is a callback function which determines whether the iteration can continue. The final parameter is the data passed to the callback function.

To iterate over the array and to print the data of each array element use:

[...]
// Callback function
static Eina_Bool
elm_print(const void *container, void *data, void *fdata)
{
   printf("%s\n", (char *)data);
 
   return EINA_TRUE;
}
 
int iterating_array()
{
   Eina_Array *array;
   unsigned int i;
 
   // Creating and populating an array
 
   // Iterating over the array and calling elm_print on each element
   eina_array_foreach(array, elm_print, NULL);
 
   // Freeing the element data and array
 
   return 0;
}
[...]

Use the eina_array_iterator_new() Function

This function returns a newly allocated iterator associated with the array. If the array is NULL or the count of the array elements is less than or equal to 0, the function returns NULL. If the memory cannot be allocated, NULL is returned and EINA_ERROR_OUT_OF_MEMORY occurs. Otherwise, a valid iterator is returned. Pass the array for which you want to create a new iterator to this function. The iterator is used to run a sequential walk through the array just like the eina_array_foreach() function.

To create an iterator and use it to print the data of each array element try:

[...]
static Eina_Bool
print_one(const void *container, void *data, void *fdata)
{
   printf("%s\n", (char*)data);
 
   return EINA_TRUE;
}
 
int new_iterator()
{
   Eina_Array *array;
   Eina_Iterator *it;
   unsigned short int i;
   void *uninteresting;
   Eina_Bool rt;
 
   // Creating and populating an array
 
   it = eina_array_iterator_new(array);
 
   it = eina_iterator_next(it, &uninteresting);
   eina_iterator_foreach(it, print_one, NULL);
   eina_iterator_free(it);
 
   return 0;
}
[...]

Use the eina_array_accessor_new() Function to Randomly access Array Elements

This function returns a newly allocated accessor associated with the array. If the array is NULL or the counting of array elements is less than or equal to 0, this function returns NULL. If the memory cannot be allocated, NULL is returned and EINA_ERROR_OUT_OF_MEMORY appears. Otherwise, a valid accessor is returned.

To use the accessor to retrieve and print the data of every other array element use:

[...]
int random_access()
{
   Eina_Array *array;       // Declaration of the array
   Eina_Accessor *acc;      // Declaration of the accessor
 
   unsigned short int i;    // Generic counter
 
   void *data;              // Variable to put the data retrieved from an array element
 
   // Creating and populating an array
 
   // Creating the array accessor
   acc = eina_array_accessor_new(array);
 
   // Random access to the data of the array elements
   for(i = 1; i < 10; i += 2)
   {
      // Putting the data in the variable 'data'
      eina_accessor_data_get(acc, i, &data);
      printf("%s\n", (const char *)data);
   }
 
   eina_accessor_free(acc);   // Freeing the accessor
 
   // Freeing the array
   return 0;
}
[...]

Create and Destroy Inline Arrays

An inline array is a container that stores the data itself, not the pointers to it. This means there is no memory fragmentation. For small data types such as char, short, and int this is more memory-efficient as data is stored in the cache and is faster to access. The bigger the data gets, however, the less efficient this becomes.

To create an inline array, use the eina_inarray_new() function. The first parameter of this function is the size of the value. In this example, only the characters are stored, and because of that, only sizeof(char) is passed to the function. The second parameter defines the size of the array allocation step. For example, if you set it to 4, the function returns an inline array of 4 elements, and the next time you grow the inline array, it grows by 4 elements and becomes an array of 8 elements. If you set the step to 0, the function sets a default safe value. The step can be changed later on using the eina_inarray_step_set() function.

The eina_inarray_new() function returns a pointer to the new Eina_Inarray variable.

[...]
int inline_array()
{
   Eina_Inarray *iarr;                        // Declare an inline array variable of the type Eina_Inarray
 
   iarr = eina_inarray_new(sizeof(char), 0);  // Create an inline array of "char"
 
   eina_inarray_free(iarr);                   // When no longer needed, free the array memory
 
   return 0;
}
[...]

Modify Inline Array Content

Add Data to the end of an Inline Array

Use the eina_inarray_push() function. The first parameter is a pointer to the array variable returned by the eina_inarray_new() function. The second parameter is the data you want to push to the inline array.

If everything runs fine, the function returns the index of the new element. If something goes wrong, it returns -1.

[...]
ch = 'a';
eina_inarray_push(iarr, &ch);
[...]

Insert Data at a Given Position within an Inline Array

Use the eina_inarray_insert_at() function. The first parameter is a pointer to the array variable returned by the eina_inarray_new() function. The second parameter is the index of the element you want to add to the inline array. The last parameter is a pointer to the content to be added.

The content of the pointer is copied to the given position in the inline array. All the elements from the position at the end of the array are shifted towards the end. If the position is equal to the end of the array, the element is appended. If the position is bigger than the array length, the function fails:

[...]
ch = 'a';
eina_inarray_push(iarr, &ch);
ch = 'b';
eina_inarray_push(iarr, &ch);
ch = 'd';
eina_inarray_push(iarr, &ch);
 
// Adding data on position 3
ch = 'c';
eina_inarray_insert_at(iarr, 2, &ch)
[...]

Insert Data Using your own Position Criteria

Use the eina_inarray_insert() or eina_inarray_insert_sorted() function. The only difference between these functions is that the eina_inarray_insert_sorted() function assumes that the array is already sorted and consequently optimizes the insertion position by doing a binary search.

In both functions the first parameter is a pointer to the array variable returned by the eina_inarray_new() function. The second parameter is the data you want to push to the inline array. The last parameter is the callback comparison function.

The Eina_Compare_Cb callback function compares data1 and data2, data1 being the value contained in the inline array and data2 the data you pass to the eina_inarray_insert() or eina_inarray_insert_sorted() function as the second parameter. If data1 is less than data2 the function returns -1. If it is greater it returns 1. If they are equal it returns 0.

The following example shows how to insert a value before a greater value:

[...]
// Defining the comparison function with the position criteria
Eina_Compare_Cb cmp(const void *a, const void *b)
{
   return *(int*)a > *(int*)b;
}
 
int inline_insert()
{
   Eina_Inarray *iarr;
   char ch, *ch3;
   int a, *b;
 
   // Creating an inline array
 
   // Adding data to the inline array
   a = 97;
   eina_inarray_push(iarr, &a);
   a = 98;
   eina_inarray_push(iarr, &a);
   a = 100;
   eina_inarray_push(iarr, &a);
 
   // Inserting data with the criteria
   a = 99;
   eina_inarray_insert_sorted(iarr, &a, cmp);
 
   eina_inarray_free(iarr);
}
[...]

Remove the Last Element from an Inline Array

Use the eina_inarray_pop() function. The only parameter is a pointer to the array variable returned by the eina_inarray_new() function. This function returns the data removed from the inline array.

[...]
eina_inarray_pop(iarr);
[...]

Remove Specific Data from an Inline Array

Use the eina_inarray_remove() function. The first parameter is a pointer to the array variable returned by the eina_inarray_new() function. The second parameter is the data you want to remove from the inline array.

The eina_inarray_remove() function finds the data and removes the matching elements from the array. The data can be an existing element of an inline array for optimized usage. In other cases, the content is matched using the memcmp() function.

The eina_inarray_remove() function returns the index of the removed element, or -1 if it failed.

[...]
iarr = eina_inarray_new(sizeof(char), 0);
 
ch = 'a';
eina_inarray_push(iarr, &ch);
 
// Removing data from the array
eina_inarray_remove(iarr, &ch);
[...]

Remove Data from a Specific Position within an Inline Array

Use the eina_inarray_remove_at() function. The first parameter is a pointer to the array variable returned by the eina_inarray_new() function. The second parameter is the index of the element you want to remove from the inline array.

The function returns EINA_TRUE on success and EINA_FALSE if something goes wrong. The element is removed from the inline array and any elements after it are moved forward towards the array head:

[...]
// Removing data from position 2
eina_inarray_remove_at(iarr, 2);
[...]

Remove all Elements from an Array

Use the eina_inarray_flush() function. The first parameter is a pointer to the array variable returned by the eina_inarray_new() function. The function removes every element from the array:

[...]
eina_inarray_flush(iarr);
[...]

Replace Values in an Inline Array

Use the eina_inarray_replace_at() function, which copies the data over the given position. The first parameter is a pointer to the array variable returned by the eina_inarray_new() function. The second parameter is the index of the element you want to remove from the inline array. The last parameter is the data you want to copy in place of the current data.

The function returns EINA_TRUE on success, and EINA_FALSE on failure. The given pointer content is copied to the given position in the array. The pointer is not referenced, instead its contents are copied to the element's array using the previously defined member_size. If the position does not exist, the function fails:

[...]
// Replacing the element at position 3
ch = 'd';
eina_inarray_replace_at(iarr, 3, &ch);
[...]

Sort an Inline Array

Use the eina_inarray_sort() function, which applies a quick sorting algorithm to the inline array. The first parameter is a pointer to the array returned by the eina_inarray_new() function. The last parameter is the Eina_Compare_Cb callback comparison function, which compares data1 and data2. These are values contained in the inline array. If the data matches, the function returns 0. If data1 is smaller than data2, it returns -1. If it is greater it returns 1.

[...]
static int
short_cmp(const void *pa, const void *pb)
{
   const short *a = pa, *b = pb;
 
   return *a - *b;
}
 
int sorting_inline_array()
{
   Eina_Inarray *array;
   int i;
 
   // Creating and populating the inline array
 
   eina_inarray_sort(array, short_cmp);
   eina_inarray_free(array);
}
[...]

Remember that the data given to the compare function is the pointer to the element memory itself. Do not change it.

Accessi Inline Array Data

Search for an element in an Inline Array

Use the eina_inarray_search() function that runs a linear walk looking for the given data.

The first parameter is a pointer to the array variable returned by the eina_inarray_new() function. The second parameter is the data used by the callback function to run the comparison. The last parameter is the Eina_Compare_Cb callback comparison function, which compares data1 and data2. data1 is the value contained in the inline array and data2 is the data you pass to the eina_inarray_search() function as the second parameter. If the data matches the function returns 0. If data1 is smaller than data2 it returns -1. If it is greater, it returns 1.

The function returns the element index, or -1 if not found.

[...]
 
Eina_Compare_Cb
compare(const void *pa, const void *pb)
{
   const short *a = pa, *b = pb;
   if (*a == *b)
        return EINA_TRUE;
 
   return EINA_FALSE;
}
 
int search_inline_array()
{
   Eina_Inarray *array;
   int i;
   int elm_index;
   int to_search = 3;
 
   // Creating and populating the inline array
 
   elm_index = eina_inarray_search(array, &to_search, compare);
   eina_inarray_free(array);
}
[...]

Remember that the data given to the compare function is the pointer to the element memory itself. Do not change it.

The eina_inarray_search_sorted() function does exactly the same as eina_inarray_search() but executes a binary search for the given data.

Retrieve the Number of Elements in an Inline Array

Use the eina_inarray_count(). The parameter is a pointer to the array returned by the eina_inarray_new() function. The function returns an unsigned int, the number of elements.

[...]
printf("Inline array of integers with %d elements:\n", eina_inarray_count(iarr));
[...]

Iterating over an Inline Array

You can use two methods to iterate over the items contained in an inline array:

  1. You can use the iterator macros for the inline arrays: FOREACH and REVERSE_FOREACH.

  2. Running a linear walk over an array of elements, use the EINA_INARRAY_FOREACH() macro. The first parameter is a pointer to the array variable returned by eina_inarray_new(), and the second parameter is the variable into which the current value is put during the walk. The EINA_INARRAY_REVERSE_FOREACH() macro does the same thing but starts from the last element.

The following example illustrates the printing of each element and its pointer:

[...]
iarr = eina_inarray_new(sizeof(char), 0);
int a, *b;
 
a = 97;
eina_inarray_push(iarr, &a);
a = 98;
eina_inarray_push(iarr, &a);
a = 99;
eina_inarray_push(iarr, &a);
 
EINA_INARRAY_FOREACH(iarr, b)
  printf("int: %d(pointer: %p)\n", *b, b);
[...]

To process the array data, use the eina_inarray_foreach() function, which invokes the given function on each element of the array with the given data. The first parameter is a pointer to the array variable returned by eina_inarray_new(). The second parameter is the function to run on each element. The function must return EINA_TRUE as long as you want to continue iterating. By returning EINA_FALSE, you stop the iteration and make the eina_inarray_foreach() function return EINA_FALSE. The data given to the function is the pointer to the element itself.

The last parameter is the data passed to the function called on each element.

The eina_inarray_foreach() function returns EINA_TRUE if it successfully iterates through all items of the array. Call the function for every given data in the array. This is a safe way to iterate over an array.

[...]
static Eina_Bool
array_foreach(const void *array __UNUSED__, void *p, void *user_data __UNUSED__)
{
   short *member = p;
   int *i = user_data;
   (*p)++;
   (*i)++;
 
   return EINA_TRUE;
}
 
int inline_array_foreach()
{
   Eina_Inarray *iarr;
   iarr = eina_inarray_new(sizeof(char), 1);
   int i;
 
   for (i = 0; i < numbers_count; i++)
     {
        short val = i;
        eina_inarray_push(iarr, &val);
     }
 
   i = 0;
   eina_inarray_foreach(iarr, array_foreach, &i);
 
   eina_inarray_free(iarr);
 
   return 0;
}
[...]

Remove some Elements Based on Your Own Criteria

Use the eina_inarray_foreach_remove() function, which walks through the array. If a value matches in the callback function the function removes the element. The first parameter is a pointer to the array returned by eina_inarray_new() function. The second parameter is the callback function to run on each element. \ \ The callback function returns EINA_TRUE if the value matches, or EINA_FALSE if it does not match. The last parameter is the data passed to the callback function.

The function returns the number of removed entries or -1 if something goes wrong.

[...]
static Eina_Bool
array_foreach(const void *array __UNUSED__, void *p, void *user_data __UNUSED__)
{
   short *member = p;
   int *i = user_data;
   if (*i == *p)
        return EINA_TRUE;
 
   return EINA_FALSE;
}
 
int inline_array_foreach_remove()
{
   Eina_Inarray *iarr;
   iarr = eina_inarray_new(sizeof(char), 1);
   int i;
 
   for (i = 0; i < numbers_count; i++)
     {
        short val = i;
        eina_inarray_push(iarr, &val);
     }
 
   i = 6;
   eina_inarray_foreach_remove(iarr, array_foreach, &i);
 
   eina_inarray_free(iarr);
 
   return 0;
}
[...]

Further Reading

Array API
A reference for the Array API.
Inline Array API
A reference for the Inline Array API.
Array Example
An example use of the Array API.