forked from enlightenment/efl
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:
parent
9a3570bfb9
commit
e3cce7b79d
|
@ -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)++)
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
|
|
@ -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)))
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue