Add eina_list test suite. Cleanup list implementation and share out of memory error.

SVN revision: 35378
This commit is contained in:
Cedric BAIL 2008-08-07 13:09:09 +00:00
parent d2f17c1e81
commit f193096aa8
8 changed files with 342 additions and 153 deletions

View File

@ -44,6 +44,8 @@ typedef enum _Eina_Error_Level
typedef int Eina_Error;
EAPI extern int EINA_ERROR_OUT_OF_MEMORY;
EAPI int eina_error_init(void);
EAPI int eina_error_shutdown(void);
EAPI Eina_Error eina_error_register(const char *msg);

View File

@ -28,6 +28,9 @@
typedef struct _Eina_List Eina_List;
EAPI int eina_list_init(void);
EAPI int eina_list_shutdown(void);
EAPI Eina_List *eina_list_append (Eina_List *list, const void *data);
EAPI Eina_List *eina_list_prepend (Eina_List *list, const void *data);
EAPI Eina_List *eina_list_append_relative (Eina_List *list, const void *data, const void *relative);
@ -49,7 +52,6 @@ EAPI void *eina_list_nth(const Eina_List *list, int n);
EAPI Eina_List *eina_list_nth_list (const Eina_List *list, int n);
EAPI Eina_List *eina_list_reverse (Eina_List *list);
EAPI Eina_List *eina_list_sort (Eina_List *list, int size, int(*func)(void*,void*));
EAPI int eina_list_alloc_error(void);
/** @} */

View File

@ -40,6 +40,7 @@ static Eina_Error _err;
#define WHITE "\033[37;1m"
#define NOTHING "\033[0m"
int EINA_ERROR_OUT_OF_MEMORY = 0;
#ifdef DEBUG
static Eina_Error_Level _error_level = EINA_ERROR_LEVEL_DBG;
@ -82,6 +83,7 @@ EAPI int eina_error_init(void)
{
_error_level = atoi(level);
}
EINA_ERROR_OUT_OF_MEMORY = eina_error_register("Out of memory");
}
/* get all the modules */
return ++_init_count;

View File

@ -52,9 +52,19 @@
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <assert.h>
#include "eina_error.h"
#include "eina_list.h"
#include "eina_private.h"
/*============================================================================*
* Local *
*============================================================================*/
struct _Eina_List /** A linked list node */
{
void *data; /**< Pointer to list element payload */
@ -64,38 +74,72 @@ struct _Eina_List /** A linked list node */
};
typedef struct _Eina_List_Accounting Eina_List_Accounting;
struct _Eina_List_Accounting
{
Eina_List *last;
int count;
};
static int _eina_list_alloc_error = 0;
typedef struct _Eina_Mempool2 Eina_Mempool2;
struct _Eina_Mempool2
static inline Eina_List_Accounting*
_eina_list_mempool_accounting_new(__UNUSED__ Eina_List *list)
{
int item_size;
int pool_size;
int usage;
void *first, *last;
};
Eina_List_Accounting *tmp;
void *_mempool2_malloc(Eina_Mempool2 *pool, int size)
{
return malloc(size);
tmp = malloc(sizeof (Eina_List_Accounting));
if (!tmp) eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
return tmp;
}
void _mempool2_free(Eina_Mempool2 *pool, void *ptr)
static inline void
_eina_list_mempool_accounting_free(Eina_List_Accounting *accounting)
{
free(ptr);
}
void *_mempool2_calloc(Eina_Mempool2 *pool, int size)
{
return calloc(1, size);
free(accounting);
}
static inline Eina_List*
_eina_list_mempool_list_new(__UNUSED__ Eina_List *list)
{
Eina_List *tmp;
tmp = malloc(sizeof (Eina_List));
if (!tmp) eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
return tmp;
}
static inline void
_eina_list_mempool_list_free(Eina_List *list)
{
list->accounting->count--;
if (list->accounting->count == 0)
_eina_list_mempool_accounting_free(list->accounting);
free(list);
}
static Eina_List *
_eina_list_setup_accounting(Eina_List *list)
{
list->accounting = _eina_list_mempool_accounting_new(list);
if (!list->accounting) goto on_error;
list->accounting->last = list;
list->accounting->count = 1;
return list;
on_error:
_eina_list_mempool_list_free(list);
return NULL;
}
static inline void
_eina_list_update_accounting(Eina_List *list, Eina_List *new_list)
{
list->accounting->count++;
new_list->accounting = list->accounting;
}
#if 0
static Eina_Mempool2 _eina_list_mempool =
{
sizeof(Eina_List),
@ -108,12 +152,30 @@ static Eina_Mempool2 _eina_list_accounting_mempool =
80,
0, NULL, NULL
};
#endif
/*============================================================================*
* Global *
*============================================================================*/
/*============================================================================*
* API *
*============================================================================*/
/**
* @defgroup Eina_List_Data_Group Linked List Creation Functions
*
* Functions that add data to an Eina_List.
*/
EAPI int
eina_list_init(void)
{
return eina_error_init();
}
EAPI int
eina_list_shutdown(void)
{
return eina_error_shutdown();
}
/**
* Appends the given data to the given linked list.
@ -146,35 +208,24 @@ eina_list_append(Eina_List *list, const void *data)
{
Eina_List *l, *new_l;
_eina_list_alloc_error = 0;
new_l = _mempool2_malloc(&_eina_list_mempool, sizeof(Eina_List));
if (!new_l)
{
_eina_list_alloc_error = 1;
return list;
}
eina_error_set(0);
new_l = _eina_list_mempool_list_new(list);
if (!new_l) return list;
new_l->next = NULL;
new_l->data = (void *)data;
if (!list)
{
new_l->prev = NULL;
new_l->accounting = _mempool2_malloc(&_eina_list_accounting_mempool, sizeof(Eina_List_Accounting));
if (!new_l->accounting)
{
_eina_list_alloc_error = 1;
_mempool2_free(&_eina_list_mempool, new_l);
return list;
}
new_l->accounting->last = new_l;
new_l->accounting->count = 1;
return new_l;
return _eina_list_setup_accounting(new_l);
}
l = list->accounting->last;
list->accounting->last = new_l;
l->next = new_l;
new_l->prev = l;
new_l->accounting = list->accounting;
list->accounting->last = new_l;
list->accounting->count++;
_eina_list_update_accounting(list, new_l);
return list;
}
@ -209,33 +260,20 @@ eina_list_prepend(Eina_List *list, const void *data)
{
Eina_List *new_l;
_eina_list_alloc_error = 0;
new_l = _mempool2_malloc(&_eina_list_mempool, sizeof(Eina_List));
if (!new_l)
{
_eina_list_alloc_error = 1;
return list;
}
eina_error_set(0);
new_l = _eina_list_mempool_list_new(list);
if (!new_l) return list;
new_l->prev = NULL;
new_l->data = (void *)data;
if (!list)
{
new_l->next = NULL;
new_l->accounting = _mempool2_malloc(&_eina_list_accounting_mempool, sizeof(Eina_List_Accounting));
if (!new_l->accounting)
{
_eina_list_alloc_error = 1;
_mempool2_free(&_eina_list_mempool, new_l);
return list;
}
new_l->accounting->last = new_l;
new_l->accounting->count = 1;
return new_l;
}
new_l->next = list;
new_l->data = (void *)data;
if (!list) return _eina_list_setup_accounting(new_l);
list->prev = new_l;
new_l->accounting = list->accounting;
list->accounting->count++;
_eina_list_update_accounting(list, new_l);
return new_l;
}
@ -293,30 +331,26 @@ EAPI Eina_List *
eina_list_append_relative_list(Eina_List *list, const void *data, Eina_List *relative)
{
Eina_List *new_l;
if ((!list) || (!relative)) return eina_list_append(list, data);
_eina_list_alloc_error = 0;
new_l = _mempool2_malloc(&_eina_list_mempool, sizeof(Eina_List));
if (!new_l)
{
_eina_list_alloc_error = 1;
return list;
}
eina_error_set(0);
new_l = _eina_list_mempool_list_new(list);
if (!new_l) return list;
new_l->next = relative->next;
new_l->data = (void *)data;
if (relative->next)
{
new_l->next = relative->next;
relative->next->prev = new_l;
}
else
new_l->next = NULL;
relative->next->prev = new_l;
relative->next = new_l;
new_l->prev = relative;
new_l->accounting = list->accounting;
list->accounting->count++;
_eina_list_update_accounting(list, new_l);
if (!new_l->next)
new_l->accounting->last = new_l;
return list;
}
@ -369,7 +403,6 @@ eina_list_prepend_relative(Eina_List *list, const void *data, const void *relati
{
Eina_List *l;
_eina_list_alloc_error = 0;
for (l = list; l; l = l->next)
{
if (l->data == relative)
@ -382,24 +415,24 @@ EAPI Eina_List *
eina_list_prepend_relative_list(Eina_List *list, const void *data, Eina_List *relative)
{
Eina_List *new_l;
if ((!list) || (!relative)) return eina_list_prepend(list, data);
_eina_list_alloc_error = 0;
new_l = _mempool2_malloc(&_eina_list_mempool, sizeof(Eina_List));
if (!new_l)
{
_eina_list_alloc_error = 1;
return list;
}
new_l->data = (void *)data;
eina_error_set(0);
new_l = _eina_list_mempool_list_new(list);
if (!new_l) return list;
new_l->prev = relative->prev;
new_l->next = relative;
new_l->data = (void *)data;
if (relative->prev) relative->prev->next = new_l;
relative->prev = new_l;
new_l->accounting = list->accounting;
list->accounting->count++;
_eina_list_update_accounting(list, new_l);
if (new_l->prev)
return list;
return new_l;
}
@ -478,10 +511,8 @@ eina_list_remove_list(Eina_List *list, Eina_List *remove_list)
return_l = remove_list->next;
if (remove_list == list->accounting->last)
list->accounting->last = remove_list->prev;
list->accounting->count--;
if (list->accounting->count == 0)
_mempool2_free(&_eina_list_accounting_mempool, list->accounting);
_mempool2_free(&_eina_list_mempool, remove_list);
_eina_list_mempool_list_free(remove_list);
return return_l;
}
@ -516,26 +547,27 @@ eina_list_remove_list(Eina_List *list, Eina_List *remove_list)
EAPI Eina_List *
eina_list_promote_list(Eina_List *list, Eina_List *move_list)
{
Eina_List *return_l;
if (!list) return NULL;
if (!move_list) return list;
/* Promoting head to be head. */
if (move_list == list) return list;
if (move_list->next) move_list->next->prev = move_list->prev;
if (move_list->prev)
{
move_list->prev->next = move_list->next;
return_l = list;
}
else
return_l = move_list->next;
/* Update pointer to the last entry if necessary. */
if (move_list == list->accounting->last)
list->accounting->last = move_list->prev;
move_list->prev = return_l->prev;
if (return_l->prev)
return_l->prev->next = move_list;
return_l->prev = move_list;
move_list->next = return_l;
/* Remove the promoted item from the list. */
if (move_list->next) move_list->next->prev = move_list->prev;
if (move_list->prev) move_list->prev->next = move_list->next;
else list = move_list->next;
assert(list);
move_list->prev = list->prev;
if (list->prev)
list->prev->next = move_list;
list->prev = move_list;
move_list->next = list;
return move_list;
}
@ -639,12 +671,12 @@ eina_list_free(Eina_List *list)
Eina_List *l, *free_l;
if (!list) return NULL;
_mempool2_free(&_eina_list_accounting_mempool, list->accounting);
for (l = list; l;)
{
free_l = l;
l = l->next;
_mempool2_free(&_eina_list_mempool, free_l);
_eina_list_mempool_list_free(free_l);
}
return NULL;
}
@ -864,7 +896,7 @@ eina_list_nth_list(const Eina_List *list, int n)
const Eina_List *l;
/* check for non-existing nodes */
if ((!list) || (n < 0) ||
if ((!list) || (n < 0) ||
(n > (list->accounting->count - 1)))
return NULL;
@ -875,7 +907,7 @@ eina_list_nth_list(const Eina_List *list, int n)
{
for (i = list->accounting->count - 1,
l = list->accounting->last;
l;
l;
l = l->prev, i--)
{
if (i == n) return (Eina_List *)l;
@ -888,7 +920,7 @@ eina_list_nth_list(const Eina_List *list, int n)
if (i == n) return (Eina_List *)l;
}
}
return NULL;
abort();
}
/**
@ -978,10 +1010,9 @@ eina_list_sort(Eina_List *list, int size, int (*func)(void *, void *))
Eina_List* last;
unsigned int list_number;
unsigned int middle;
int list_size;
unsigned int list_size;
if (!list || !func)
return NULL;
if (!list || !func) return NULL;
/* if the caller specified an invalid size, sort the whole list */
if ((size <= 0) ||
@ -1074,33 +1105,3 @@ eina_list_sort(Eina_List *list, int size, int (*func)(void *, void *))
list->accounting->last = last;
return list;
}
/**
* Return the memory allocation failure flag after any operation needin allocation
* @return The state of the allocation flag
*
* This function returns the state of the memory allocation flag. This flag is
* set if memory allocations during eina_list_append(), eina_list_prepend(),
* eina_list_append_relative(), or eina_list_prepend_relative() fail. If they
* do fail, 1 will be returned, otherwise 0 will be returned. The flag will
* remain in its current state until the next call that requires allocation
* is called, and is then reset.
*
* Example:
* @code
* Eina_List *list = NULL;
* extern void *my_data;
*
* list = eina_list_append(list, my_data);
* if (eina_list_alloc_error())
* {
* fprintf(stderr, "ERROR: Memory is low. List allocation failed.\n");
* exit(-1);
* }
* @endcode
* @ingroup Eina_List_General_Group
*/
EAPI int
eina_list_alloc_error(void)
{
return _eina_list_alloc_error;
}

View File

@ -21,7 +21,8 @@ eina_test_inlist.c \
eina_test_main.c \
eina_test_counter.c \
eina_test_lalloc.c \
eina_test_hash.c
eina_test_hash.c \
eina_test_list.c
eina_suite_LDADD = @CHECK_LIBS@ $(top_builddir)/src/lib/libeina.la

View File

@ -35,6 +35,7 @@ static const Eina_Test_Case etc[] = {
{ "Main", eina_test_main },
{ "Counter", eina_test_counter },
{ "Hash", eina_test_hash },
{ "List", eina_test_list },
{ NULL, NULL }
};

View File

@ -34,5 +34,6 @@ void eina_test_lalloc(TCase *tc);
void eina_test_main(TCase *tc);
void eina_test_counter(TCase *tc);
void eina_test_hash(TCase *tc);
void eina_test_list(TCase *tc);
#endif /* EINA_SUITE_H_ */

View File

@ -0,0 +1,179 @@
/* EINA - EFL data type library
* Copyright (C) 2008 Cedric Bail
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library;
* if not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include "eina_list.h"
#include "eina_suite.h"
static int eina_int_cmp(void *a, void *b)
{
int *ia = a;
int *ib = b;
return *ia - *ib;
}
START_TEST(eina_test_simple)
{
Eina_List *list = NULL;
Eina_List *tmp;
int *test1;
int *test2;
int *test3;
int data[] = { 6, 9, 42, 1, 7, 9, 81, 1664, 1337 };
int result[] = { 81, 9, 9, 7, 1 };
int i;
eina_list_init();
list = eina_list_append(list, &data[0]);
fail_if(list == NULL);
list = eina_list_prepend(list, &data[1]);
fail_if(list == NULL);
list = eina_list_append(list, &data[2]);
fail_if(list == NULL);
list = eina_list_remove(list, &data[0]);
fail_if(list == NULL);
list = eina_list_remove(list, &data[0]);
fail_if(list == NULL);
tmp = eina_list_find_list(list, &data[2]);
fail_if(tmp == NULL);
list = eina_list_append_relative_list(list, &data[3], tmp);
fail_if(list == NULL);
list = eina_list_prepend_relative_list(list, &data[4], tmp);
fail_if(list == NULL);
list = eina_list_promote_list(list, tmp);
fail_if(list == NULL);
list = eina_list_append_relative(list, &data[5], &data[2]);
fail_if(list == NULL);
list = eina_list_prepend_relative(list, &data[6], &data[2]);
fail_if(list == NULL);
list = eina_list_remove_list(list, tmp);
fail_if(list == NULL);
fail_if(eina_list_find_list(list, &data[2]) != NULL);
fail_if(eina_list_find(list, &data[2]) != NULL);
fail_if(eina_list_find(list, &data[5]) != &data[5]);
fail_if(eina_list_count(list) != 5);
fail_if(eina_list_nth(list, 4) != &data[3]);
fail_if(eina_list_nth(list, 10) != NULL);
fail_if(eina_list_nth_list(list, 10) != NULL);
for (tmp = list, i = 0; tmp != NULL; tmp = eina_list_next(tmp), ++i)
{
int *data;
data = eina_list_data(tmp);
fail_if(data == NULL);
fail_if(*data != result[i]);
}
list = eina_list_reverse(list);
for (tmp = list; tmp != NULL; tmp = eina_list_next(tmp), --i)
{
int *data;
data = eina_list_data(tmp);
fail_if(data == NULL);
fail_if(*data != result[i - 1]);
}
list = eina_list_append_relative(list, &data[7], &data[7]);
fail_if(list == NULL);
list = eina_list_prepend_relative(list, &data[8], &data[8]);
fail_if(list == NULL);
list = eina_list_sort(list, 2, eina_int_cmp);
test1 = eina_list_nth(list, 0);
test2 = eina_list_nth(list, 1);
test3 = eina_list_nth(list, 2);
fail_if(test1 == NULL || test2 == NULL || test3 == NULL);
fail_if(*test1 > *test2);
fail_if(*test3 == *test2);
list = eina_list_append(list, &data[8]);
fail_if(list == NULL);
list = eina_list_append(list, &data[7]);
fail_if(list == NULL);
list = eina_list_sort(list, -1, eina_int_cmp);
test1 = eina_list_nth(list, 0);
for (tmp = list; tmp != NULL; tmp = eina_list_next(tmp))
{
int *data;
data = eina_list_data(tmp);
fail_if(*test1 > *data);
test1 = data;
}
test3 = eina_list_nth(list, 5);
fail_if(test3 == NULL);
list = eina_list_promote_list(list, list);
fail_if(list == NULL);
list = eina_list_promote_list(list, eina_list_last(list));
fail_if(list == NULL);
test1 = eina_list_nth(list, 0);
test2 = eina_list_nth(list, 1);
list = eina_list_promote_list(eina_list_next(list), list);
fail_if(list == NULL);
fail_if(eina_list_data(list) != test1);
fail_if(eina_list_data(eina_list_next(list)) != test2);
list = eina_list_remove_list(list, list);
fail_if(list == NULL);
list = eina_list_remove_list(list, eina_list_last(list));
fail_if(list == NULL);
list = eina_list_free(list);
fail_if(list != NULL);
eina_list_shutdown();
}
END_TEST
void
eina_test_list(TCase *tc)
{
tcase_add_test(tc, eina_test_simple);
}