New macros, documentation and consistency for iterators and accessors.

EINA_ITERATOR_FOREACH() and EINA_ACCESSOR_FOREACH() are new macros to
help us forget about nasty C details (like cast to (void **)).

Document most iterators and accessors.

All iterators now set EINA_ERROR_OUT_OF_MEMORY if it's the case.



SVN revision: 39267
This commit is contained in:
Gustavo Sverzut Barbieri 2009-02-27 16:32:22 +00:00
parent 9a3570bfb9
commit e3cce7b79d
6 changed files with 283 additions and 15 deletions

View File

@ -66,6 +66,55 @@ EAPI void eina_accessor_over (Eina_Accessor *accessor,
unsigned int end,
const void *fdata) EINA_ARG_NONNULL(1, 2);
/**
* @def EINA_ACCESSOR_FOREACH
* @brief Macro to iterate over all elements easily.
*
* @param accessor The accessor to use.
* @param data Where to store * data, must be a pointer support getting
* its address since * eina_accessor_data_get() requires a pointer
* to pointer!
*
* This macro is a convenient way to loop over all elements in an
* accessor, very similar to EINA_LIST_FOREACH().
*
* This macro can be used for freeing the data of a list, like in the
* following example. It has the same goal as the one documented in
* EINA_LIST_FOREACH(), but using accessors:
*
* @code
* Eina_List *list;
* Eina_Accessor *accessor;
* unsigned int i;
* char *data;
*
* // list is already filled,
* // its elements are just duplicated strings
*
* accessor = eina_list_accessor_new(list);
* EINA_ACCESSOR_FOREACH(accessor, i, data)
* free(data);
* eina_accessor_free(accessor);
* eina_list_free(list);
* @endcode
*
* @note if the datatype provides both iterators and accessors prefer
* to use iterators to iterate over, as they're likely to be more
* optimized for such task.
*
* @note this example is not optimal algorithm to release a list since
* it will walk the list twice, but it serves as an example. For
* optimized version use EINA_LIST_FREE()
*
* @warning unless explicitly stated in functions returning accessors,
* do not modify the accessed object while you walk it, in this
* example using lists, do not remove list nodes or you might
* crash! This is not a limitiation of accessors themselves,
* rather in the accessors implementations to keep them as simple
* and fast as possible.
*/
#define EINA_ACCESSOR_FOREACH(accessor, counter, data) for ((counter) = 0; eina_accessor_data_get((accessor), (counter), (void **)&(data)); (counter)++)
/**
* @}
*/

View File

@ -64,6 +64,50 @@ EAPI void eina_iterator_foreach (Eina_Iterator *iterator,
Eina_Each callback,
const void *fdata) EINA_ARG_NONNULL(1, 2);
/**
* @def EINA_ITERATOR_FOREACH
* @brief Macro to iterate over all elements easily.
*
* @param iterator The iterator to use.
* @param data Where to store * data, must be a pointer support getting
* its address since * eina_iterator_next() requires a pointer
* to pointer!
*
* This macro is a convenient way to use iterators, very similar to
* EINA_LIST_FOREACH().
*
* This macro can be used for freeing the data of a list, like in the
* following example. It has the same goal as the one documented in
* EINA_LIST_FOREACH(), but using iterators:
*
* @code
* Eina_List *list;
* Eina_Iterator *itr;
* char *data;
*
* // list is already filled,
* // its elements are just duplicated strings
*
* itr = eina_list_iterator_new(list);
* EINA_ITERATOR_FOREACH(itr, data)
* free(data);
* eina_iterator_free(itr);
* eina_list_free(list);
* @endcode
*
* @note this example is not optimal algorithm to release a list since
* it will walk the list twice, but it serves as an example. For
* optimized version use EINA_LIST_FREE()
*
* @warning unless explicitly stated in functions returning iterators,
* do not modify the iterated object while you walk it, in this
* example using lists, do not remove list nodes or you might
* crash! This is not a limitiation of iterators themselves,
* rather in the iterators implementations to keep them as simple
* and fast as possible.
*/
#define EINA_ITERATOR_FOREACH(itr, data) while (eina_iterator_next((itr), (void **)&(data)))
/**
* @}
*/

View File

@ -137,10 +137,16 @@ EAPI Eina_Accessor *eina_list_accessor_new(const Eina_List *list) EINA_MALLOC EI
*
* EINA_LIST_FOREACH(list, l, data)
* free(data);
* eina_list_free(list);
* @endcode
*
* @warning do not delete list nodes, specially the current node, while
* iterating. If you wish to do so, use EINA_LIST_FOREACH_SAFE().
* @note this example is not optimal algorithm to release a list since
* it will walk the list twice, but it serves as an example. For
* optimized version use EINA_LIST_FREE()
*
* @warning do not delete list nodes, specially the current node,
* while iterating. If you wish to do so, use
* EINA_LIST_FOREACH_SAFE().
*/
#define EINA_LIST_FOREACH(list, l, data) for (l = list, data = eina_list_data_get(l); l; l = eina_list_next(l), data = eina_list_data_get(l))
@ -171,10 +177,16 @@ EAPI Eina_Accessor *eina_list_accessor_new(const Eina_List *list) EINA_MALLOC EI
*
* EINA_LIST_REVERSE_FOREACH(list, l, data)
* free(data);
* eina_list_free(list);
* @endcode
*
* @warning do not delete list nodes, specially the current node, while
* iterating. If you wish to do so, use EINA_LIST_REVERSE_FOREACH_SAFE().
* @note this example is not optimal algorithm to release a list since
* it will walk the list twice, but it serves as an example. For
* optimized version use EINA_LIST_FREE()
*
* @warning do not delete list nodes, specially the current node,
* while iterating. If you wish to do so, use
* EINA_LIST_REVERSE_FOREACH_SAFE().
*/
#define EINA_LIST_REVERSE_FOREACH(list, l, data) for (l = eina_list_last(list), data = eina_list_data_get(l); l; l = eina_list_prev(l), data = eina_list_data_get(l))
@ -260,6 +272,24 @@ EAPI Eina_Accessor *eina_list_accessor_new(const Eina_List *list) EINA_MALLOC EI
*/
#define EINA_LIST_REVERSE_FOREACH_SAFE(list, l, l_prev, data) for (l = list, l_prev = eina_list_prev(l), data = eina_list_data_get(l); l; l = l_prev, l_prev = eina_list_prev(l), data = eina_list_data_get(l))
/**
* Easy way to free the while list while being able to release its pointed data.
*
* @code
* Eina_List *list;
* char *data;
*
* // list is already filled,
* // its elements are just duplicated strings,
*
* EINA_LIST_FREE(list, data)
* free(data);
* @endcode
*
* If you do not need to release node data then use eina_list_free().
*
* @see eina_list_free()
*/
#define EINA_LIST_FREE(list, data) for (data = list ? eina_list_data_get(list) : NULL; list; list = eina_list_remove_list(list, list), data = list ? eina_list_data_get(list) : NULL)
#include "eina_inline_list.x"

View File

@ -277,7 +277,7 @@ _eina_hash_rbtree_each(__UNUSED__ const Eina_Rbtree *container, const Eina_Hash_
Eina_Bool found = EINA_TRUE;
it = eina_rbtree_iterator_prefix(eh->head);
while (eina_iterator_next(it, (void**) &el))
EINA_ITERATOR_FOREACH(it, el)
{
if (el->tuple.data == data->data)
{
@ -1293,6 +1293,25 @@ eina_hash_foreach(const Eina_Hash *hash,
eina_iterator_free(it);
}
/**
* @brief Returned a new iterator asociated to hash data.
*
* @param hash The hash.
* @return A new iterator.
*
* This function returns a newly allocated iterator associated to @p
* hash. If @p hash is not populated, this function still returns a
* valid iterator that will always return false on
* eina_iterator_next(), thus keeping API sane.
*
* If the memory can not be allocated, NULL is returned and
* #EINA_ERROR_OUT_OF_MEMORY is set. Otherwise, a valid iterator is
* returned.
*
* @warning if the hash structure changes then the iterator becomes
* invalid! That is, if you add or remove items this iterator
* behavior is undefined and your program may crash!
*/
EAPI Eina_Iterator *
eina_hash_iterator_data_new(const Eina_Hash *hash)
{
@ -1301,8 +1320,12 @@ eina_hash_iterator_data_new(const Eina_Hash *hash)
EINA_MAGIC_CHECK_HASH(hash);
EINA_SAFETY_ON_NULL_RETURN_VAL(hash, NULL);
eina_error_set(0);
it = calloc(1, sizeof (Eina_Iterator_Hash));
if (!it) return NULL;
if (!it) {
eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
return NULL;
}
it->hash = hash;
it->get_content = FUNC_ITERATOR_GET_CONTENT(_eina_hash_iterator_data_get_content);
@ -1317,6 +1340,25 @@ eina_hash_iterator_data_new(const Eina_Hash *hash)
return &it->iterator;
}
/**
* @brief Returned a new iterator asociated to hash keys.
*
* @param hash The hash.
* @return A new iterator.
*
* This function returns a newly allocated iterator associated to @p
* hash. If @p hash is not populated, this function still returns a
* valid iterator that will always return false on
* eina_iterator_next(), thus keeping API sane.
*
* If the memory can not be allocated, NULL is returned and
* #EINA_ERROR_OUT_OF_MEMORY is set. Otherwise, a valid iterator is
* returned.
*
* @warning if the hash structure changes then the iterator becomes
* invalid! That is, if you add or remove items this iterator
* behavior is undefined and your program may crash!
*/
EAPI Eina_Iterator *
eina_hash_iterator_key_new(const Eina_Hash *hash)
{
@ -1325,8 +1367,12 @@ eina_hash_iterator_key_new(const Eina_Hash *hash)
EINA_MAGIC_CHECK_HASH(hash);
EINA_SAFETY_ON_NULL_RETURN_VAL(hash, NULL);
eina_error_set(0);
it = calloc(1, sizeof (Eina_Iterator_Hash));
if (!it) return NULL;
if (!it) {
eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
return NULL;
}
it->hash = hash;
it->get_content = FUNC_ITERATOR_GET_CONTENT(_eina_hash_iterator_key_get_content);
@ -1341,6 +1387,28 @@ eina_hash_iterator_key_new(const Eina_Hash *hash)
return &it->iterator;
}
/**
* @brief Returned a new iterator asociated to hash keys and data.
*
* @param hash The hash.
* @return A new iterator.
*
* This function returns a newly allocated iterator associated to @p
* hash. If @p hash is not populated, this function still returns a
* valid iterator that will always return false on
* eina_iterator_next(), thus keeping API sane.
*
* If the memory can not be allocated, NULL is returned and
* #EINA_ERROR_OUT_OF_MEMORY is set. Otherwise, a valid iterator is
* returned.
*
* @note iterator data will provide values as Eina_Hash_Tuple that should not
* be modified!
*
* @warning if the hash structure changes then the iterator becomes
* invalid! That is, if you add or remove items this iterator
* behavior is undefined and your program may crash!
*/
EAPI Eina_Iterator *
eina_hash_iterator_tuple_new(const Eina_Hash *hash)
{
@ -1349,8 +1417,12 @@ eina_hash_iterator_tuple_new(const Eina_Hash *hash)
EINA_MAGIC_CHECK_HASH(hash);
EINA_SAFETY_ON_NULL_RETURN_VAL(hash, NULL);
eina_error_set(0);
it = calloc(1, sizeof (Eina_Iterator_Hash));
if (!it) return NULL;
if (!it) {
eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
return NULL;
}
it->hash = hash;
it->get_content = FUNC_ITERATOR_GET_CONTENT(_eina_hash_iterator_tuple_get_content);

View File

@ -1555,11 +1555,19 @@ eina_list_search_unsorted(const Eina_List *list, Eina_Compare_Cb func, const voi
* @param list The list.
* @return A new iterator.
*
* This function returns a newly allocated iterator associated to
* @p list. If @p list is @c NULL or the count member of @p list is
* less or equal than 0, this function returns NULL. If the memory can
* not be allocated, NULL is returned and #EINA_ERROR_OUT_OF_MEMORY is
* set. Otherwise, a valid iterator is returned.
* This function returns a newly allocated iterator associated to @p
* list. If @p list is @c NULL or the count member of @p list is less
* or equal than 0, this function still returns a valid iterator that
* will always return false on eina_iterator_next(), thus keeping API
* sane.
*
* If the memory can not be allocated, NULL is returned and
* #EINA_ERROR_OUT_OF_MEMORY is set. Otherwise, a valid iterator is
* returned.
*
* @warning if the list structure changes then the iterator becomes
* invalid! That is, if you add or remove nodes this iterator
* behavior is undefined and your program may crash!
*/
EAPI Eina_Iterator *
eina_list_iterator_new(const Eina_List *list)

View File

@ -62,8 +62,12 @@ _eina_rbtree_iterator_list_new(const Eina_Rbtree *tree)
{
Eina_Iterator_Rbtree_List *new;
eina_error_set(0);
new = malloc(sizeof (Eina_Iterator_Rbtree_List));
if (!new) return NULL;
if (!new) {
eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
return NULL;
}
new->tree = (Eina_Rbtree*) tree;
new->dir = EINA_RBTREE_RIGHT;
@ -162,8 +166,12 @@ _eina_rbtree_iterator_build(const Eina_Rbtree *root, unsigned char mask)
Eina_Iterator_Rbtree_List *first;
Eina_Iterator_Rbtree *it;
eina_error_set(0);
it = calloc(1, sizeof (Eina_Iterator_Rbtree));
if (!it) return NULL;
if (!it) {
eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
return NULL;
}
it->stack = eina_array_new(8);
if (!it->stack) goto on_error;
@ -437,18 +445,75 @@ eina_rbtree_inline_remove(Eina_Rbtree *root, Eina_Rbtree *node, Eina_Rbtree_Cmp_
return root;
}
/**
* @brief Returned a new prefix iterator asociated to a rbtree.
*
* @param root The root of rbtree.
* @return A new iterator.
*
* This function returns a newly allocated iterator associated to @p
* root. It will iterate the tree using prefix walk. If @p root is @c
* NULL, this function still returns a valid iterator that will always
* return false on eina_iterator_next(), thus keeping API sane.
*
* If the memory can not be allocated, NULL is returned and
* #EINA_ERROR_OUT_OF_MEMORY is set. Otherwise, a valid iterator is
* returned.
*
* @warning if the rbtree structure changes then the iterator becomes
* invalid! That is, if you add or remove nodes this iterator
* behavior is undefined and your program may crash!
*/
EAPI Eina_Iterator *
eina_rbtree_iterator_prefix(const Eina_Rbtree *root)
{
return _eina_rbtree_iterator_build(root, EINA_RBTREE_ITERATOR_PREFIX_MASK);
}
/**
* @brief Returned a new prefix iterator asociated to a rbtree.
*
* @param root The root of rbtree.
* @return A new iterator.
*
* This function returns a newly allocated iterator associated to @p
* root. It will iterate the tree using infix walk. If @p root is @c
* NULL, this function still returns a valid iterator that will always
* return false on eina_iterator_next(), thus keeping API sane.
*
* If the memory can not be allocated, NULL is returned and
* #EINA_ERROR_OUT_OF_MEMORY is set. Otherwise, a valid iterator is
* returned.
*
* @warning if the rbtree structure changes then the iterator becomes
* invalid! That is, if you add or remove nodes this iterator
* behavior is undefined and your program may crash!
*/
EAPI Eina_Iterator *
eina_rbtree_iterator_infix(const Eina_Rbtree *root)
{
return _eina_rbtree_iterator_build(root, EINA_RBTREE_ITERATOR_INFIX_MASK);
}
/**
* @brief Returned a new prefix iterator asociated to a rbtree.
*
* @param root The root of rbtree.
* @return A new iterator.
*
* This function returns a newly allocated iterator associated to @p
* root. It will iterate the tree using postfix walk. If @p root is @c
* NULL, this function still returns a valid iterator that will always
* return false on eina_iterator_next(), thus keeping API sane.
*
* If the memory can not be allocated, NULL is returned and
* #EINA_ERROR_OUT_OF_MEMORY is set. Otherwise, a valid iterator is
* returned.
*
* @warning if the rbtree structure changes then the iterator becomes
* invalid! That is, if you add or remove nodes this iterator
* behavior is undefined and your program may crash!
*/
EAPI Eina_Iterator *
eina_rbtree_iterator_postfix(const Eina_Rbtree *root)
{