From b87e1d6fae74fc26eea10e295027751f94020fa6 Mon Sep 17 00:00:00 2001 From: Vincent Torri Date: Sat, 13 Feb 2010 12:32:22 +0000 Subject: [PATCH] * -fno-strict-aliasing is checked at linked time (to make sure that it is disabled for suncc) * add old evas data types in tests. Tell me if you encounter problems with them SVN revision: 46136 --- legacy/eina/configure.ac | 5 +- legacy/eina/m4/efl_compiler_flag.m4 | 37 +- legacy/eina/src/tests/Evas_Data.h | 151 +++ legacy/eina/src/tests/Makefile.am | 20 +- legacy/eina/src/tests/eina_bench_array.c | 20 +- legacy/eina/src/tests/eina_bench_hash.c | 17 +- legacy/eina/src/tests/eina_bench_sort.c | 23 +- .../eina/src/tests/eina_bench_stringshare.c | 22 +- .../src/tests/eina_bench_stringshare_e17.c | 21 +- legacy/eina/src/tests/evas_hash.c | 498 ++++++++ legacy/eina/src/tests/evas_list.c | 1031 +++++++++++++++++ legacy/eina/src/tests/evas_mempool.c | 188 +++ legacy/eina/src/tests/evas_mempool.h | 25 + legacy/eina/src/tests/evas_object_list.c | 164 +++ legacy/eina/src/tests/evas_stringshare.c | 205 ++++ 15 files changed, 2326 insertions(+), 101 deletions(-) create mode 100644 legacy/eina/src/tests/Evas_Data.h create mode 100644 legacy/eina/src/tests/evas_hash.c create mode 100644 legacy/eina/src/tests/evas_list.c create mode 100644 legacy/eina/src/tests/evas_mempool.c create mode 100644 legacy/eina/src/tests/evas_mempool.h create mode 100644 legacy/eina/src/tests/evas_object_list.c create mode 100644 legacy/eina/src/tests/evas_stringshare.c diff --git a/legacy/eina/configure.ac b/legacy/eina/configure.ac index 1450a63f1f..9e093fdcd7 100644 --- a/legacy/eina/configure.ac +++ b/legacy/eina/configure.ac @@ -294,7 +294,6 @@ if ! test "x${VMIC}" = "x" ; then fi EFL_COMPILER_FLAG([-Wshadow]) -EFL_COMPILER_FLAG([-fno-strict-aliasing]) AC_SUBST(EINA_CPPFLAGS) AC_SUBST(EINA_CFLAGS) @@ -327,6 +326,8 @@ esac AC_SUBST(EINA_LIBS) AC_SUBST(lt_enable_auto_import) +EFL_LINKER_FLAG([-fno-strict-aliasing]) + ### Checks for library functions AC_FUNC_ALLOCA @@ -483,7 +484,6 @@ if test "x$enable_coverage" = "xyes" ; then fi EFL_CHECK_BENCHMARK([enable_benchmark="yes"], [enable_benchmark="no"]) -EINA_BENCH_MODULE([evas], [${enable_benchmark}], [evas], [enable_benchmark_evas="yes"], [enable_benchmark_evas="no"]) EINA_BENCH_MODULE([glib], [${enable_benchmark}], [glib-2.0], [enable_benchmark_glib="yes"], [enable_benchmark_glib="no"]) AC_SUBST(requirement_eina) @@ -554,7 +554,6 @@ echo " Coverage.............: ${enable_coverage}" echo " Benchmark............: ${enable_benchmark}" if test "x${enable_benchmark}" = "xyes" ; then echo " Glib...............: ${enable_benchmark_glib}" -echo " Evas...............: ${enable_benchmark_evas}" echo " E17 real data......: ${enable_benchmark_e17}" fi echo diff --git a/legacy/eina/m4/efl_compiler_flag.m4 b/legacy/eina/m4/efl_compiler_flag.m4 index e3fc8217b8..618c6a6847 100644 --- a/legacy/eina/m4/efl_compiler_flag.m4 +++ b/legacy/eina/m4/efl_compiler_flag.m4 @@ -1,5 +1,11 @@ -dnl Checks if a given compiler switch is supported. -dnl If so, this macro adds the flag to the CFLAGS +dnl Copyright (C) 2010 Vincent Torri +dnl and Albin Tonnerre +dnl That code is public domain and can be freely used or copied. + +dnl Macro that checks if a compiler flag is supported by the compiler. + +dnl Usage: EFL_COMPILER_FLAG(flag) +dnl flag is added to CFLAGS if supported. AC_DEFUN([EFL_COMPILER_FLAG], [ @@ -22,3 +28,30 @@ fi AC_LANG_POP([C]) ]) + +dnl Macro that checks if a linker flag is supported by the compiler. + +dnl Usage: EFL_LINKER_FLAG(flag) +dnl flag is added to CFLAGS if supported (will be passed to ld anyway). + +AC_DEFUN([EFL_LINKER_FLAG], +[ + +CFLAGS_save="${CFLAGS}" +CFLAGS="${CFLAGS} $1" + +AC_LANG_PUSH([C]) +AC_MSG_CHECKING([whether the compiler supports $1]) + +AC_LINK_IFELSE( + [AC_LANG_PROGRAM([[]])], + [have_flag="yes"], + [have_flag="no"]) +AC_MSG_RESULT([${have_flag}]) + +if test "x${have_flag}" = "xno" ; then + CFLAGS="${CFLAGS_save}" +fi +AC_LANG_POP([C]) + +]) diff --git a/legacy/eina/src/tests/Evas_Data.h b/legacy/eina/src/tests/Evas_Data.h new file mode 100644 index 0000000000..21e1131530 --- /dev/null +++ b/legacy/eina/src/tests/Evas_Data.h @@ -0,0 +1,151 @@ +#ifndef _EVAS_DATA_H +#define _EVAS_DATA_H + +#ifdef EAPI +# undef EAPI +#endif + +#ifdef _WIN32 +# ifdef EFL_EVAS_BUILD +# ifdef DLL_EXPORT +# define EAPI __declspec(dllexport) +# else +# define EAPI +# endif /* ! DLL_EXPORT */ +# else +# define EAPI __declspec(dllimport) +# endif /* ! EFL_EVAS_BUILD */ +#else +# ifdef __GNUC__ +# if __GNUC__ >= 4 +# define EAPI __attribute__ ((visibility("default"))) +# else +# define EAPI +# endif +# else +# define EAPI +# endif +#endif /* ! _WIN32 */ + +/** + * @file + * @brief These routines are used for Evas data types. + */ + +typedef unsigned char Evas_Bool; + +typedef struct _Evas_Array_Hash Evas_Array_Hash; +typedef struct _Evas_Hash Evas_Hash; /**< A Hash table handle */ +typedef struct _Evas_List Evas_List; /**< A generic linked list node handle */ +typedef struct _Evas_Object_List Evas_Object_List; + +struct _Evas_Hash +{ + int population; + Evas_Object_List *buckets[256]; +}; + +struct _Evas_List /** A linked list node */ +{ + void *data; /**< Pointer to list element payload */ + Evas_List *next; /**< Next member in the list */ + Evas_List *prev; /**< Previous member in the list */ + struct _Evas_List_Accounting *accounting; /**< Private list accounting info - don't touch */ +}; + +struct _Evas_Object_List +{ + Evas_Object_List *next, *prev; + Evas_Object_List *last; +}; + + +#ifdef __cplusplus +extern "C" { +#endif + + /* + * Evas Array Hash functions + */ + + EAPI Evas_Array_Hash *evas_array_hash_new (void); + EAPI void evas_array_hash_free (Evas_Array_Hash *hash); + EAPI void evas_array_hash_add (Evas_Array_Hash *hash, int key, int data); + EAPI int evas_array_hash_search (Evas_Array_Hash *hash, int key); + + + /* + * Evas Hash functions + */ + + /* FIXME: add: + * api to add find, del members by data, size not just string and also + * provide hash generation functions settable by the app + * + * do we really need this? hmmm - let me think... there may be a better way + */ + EAPI Evas_Hash *evas_hash_add (Evas_Hash *hash, const char *key, const void *data); + EAPI Evas_Hash *evas_hash_direct_add (Evas_Hash *hash, const char *key, const void *data); + EAPI Evas_Hash *evas_hash_del (Evas_Hash *hash, const char *key, const void *data); + EAPI void *evas_hash_find (const Evas_Hash *hash, const char *key); + EAPI void *evas_hash_modify (Evas_Hash *hash, const char *key, const void *data); + EAPI int evas_hash_size (const Evas_Hash *hash); + EAPI void evas_hash_free (Evas_Hash *hash); + EAPI void evas_hash_foreach (const Evas_Hash *hash, Evas_Bool (*func) (const Evas_Hash *hash, const char *key, void *data, void *fdata), const void *fdata); + EAPI int evas_hash_alloc_error (void); + + + /* + * Evas List functions + */ + + EAPI Evas_List *evas_list_append (Evas_List *list, const void *data); + EAPI Evas_List *evas_list_prepend (Evas_List *list, const void *data); + EAPI Evas_List *evas_list_append_relative (Evas_List *list, const void *data, const void *relative); + EAPI Evas_List *evas_list_append_relative_list (Evas_List *list, const void *data, Evas_List *relative); + EAPI Evas_List *evas_list_prepend_relative (Evas_List *list, const void *data, const void *relative); + EAPI Evas_List *evas_list_prepend_relative_list (Evas_List *list, const void *data, Evas_List *relative); + EAPI Evas_List *evas_list_remove (Evas_List *list, const void *data); + EAPI Evas_List *evas_list_remove_list (Evas_List *list, Evas_List *remove_list); + EAPI Evas_List *evas_list_promote_list (Evas_List *list, Evas_List *move_list); + EAPI void *evas_list_find (const Evas_List *list, const void *data); + EAPI Evas_List *evas_list_find_list (const Evas_List *list, const void *data); + EAPI Evas_List *evas_list_free (Evas_List *list); + EAPI Evas_List *evas_list_last (const Evas_List *list); + EAPI Evas_List *evas_list_next (const Evas_List *list); + EAPI Evas_List *evas_list_prev (const Evas_List *list); + EAPI void *evas_list_data (const Evas_List *list); + EAPI int evas_list_count (const Evas_List *list); + EAPI void *evas_list_nth (const Evas_List *list, int n); + EAPI Evas_List *evas_list_nth_list (const Evas_List *list, int n); + EAPI Evas_List *evas_list_reverse (Evas_List *list); + EAPI Evas_List *evas_list_sort (Evas_List *list, int size, int(*func)(void*,void*)); + EAPI int evas_list_alloc_error (void); + + + /* + * Evas Object List functions + */ + + EAPI void *evas_object_list_append (void *in_list, void *in_item); + EAPI void *evas_object_list_prepend (void *in_list, void *in_item); + EAPI void *evas_object_list_append_relative (void *in_list, void *in_item, void *in_relative); + EAPI void *evas_object_list_prepend_relative (void *in_list, void *in_item, void *in_relative); + EAPI void *evas_object_list_remove (void *in_list, void *in_item); + EAPI void *evas_object_list_find (void *in_list, void *in_item); + + + /* + * Evas Stringshare functions + */ + + EAPI void evas_stringshare_init (void); /* not implemented */ + EAPI void evas_stringshare_shutdown (void); /* not implemented */ + EAPI const char *evas_stringshare_add (const char *str); + EAPI void evas_stringshare_del (const char *str); + +#ifdef __cplusplus +} +#endif + +#endif /* _EVAS_DATA_H */ diff --git a/legacy/eina/src/tests/Makefile.am b/legacy/eina/src/tests/Makefile.am index c9948e06a2..842d2864ba 100644 --- a/legacy/eina/src/tests/Makefile.am +++ b/legacy/eina/src/tests/Makefile.am @@ -12,8 +12,7 @@ AM_CPPFLAGS = \ -DPACKAGE_DATA_DIR=\"$(datadir)/$(PACKAGE)\" \ -DPACKAGE_BUILD_DIR=\"`pwd`/$(top_builddir)\" \ @CHECK_CFLAGS@ \ -@GLIB_CFLAGS@ \ -@EVAS_CFLAGS@ +@GLIB_CFLAGS@ if EINA_HAVE_GLIB @@ -21,12 +20,6 @@ AM_CPPFLAGS += -DEINA_BENCH_HAVE_GLIB endif -if EINA_HAVE_EVAS - -AM_CPPFLAGS += -DEINA_BENCH_HAVE_EVAS - -endif - if EINA_ENABLE_BENCHMARK_E17 AM_CPPFLAGS += -DEINA_ENABLE_BENCH_E17 @@ -94,11 +87,16 @@ eina_bench_rectangle_pool.c \ ecore_list.c \ ecore_strings.c \ ecore_hash.c \ -ecore_sheap.c +ecore_sheap.c \ +evas_hash.c \ +evas_list.c \ +evas_mempool.c \ +evas_object_list.c \ +evas_stringshare.c -eina_bench_LDADD = @EVAS_LIBS@ @GLIB_LIBS@ $(top_builddir)/src/lib/libeina.la +eina_bench_LDADD = @GLIB_LIBS@ $(top_builddir)/src/lib/libeina.la endif -EXTRA_DIST = eina_bench.h eina_suite.h +EXTRA_DIST = eina_bench.h eina_suite.h Ecore_Data.h Evas_Data.h evas_mempool.h diff --git a/legacy/eina/src/tests/eina_bench_array.c b/legacy/eina/src/tests/eina_bench_array.c index 87ee52a82e..8ff134e223 100644 --- a/legacy/eina/src/tests/eina_bench_array.c +++ b/legacy/eina/src/tests/eina_bench_array.c @@ -28,16 +28,14 @@ # include #endif -#ifdef EINA_BENCH_HAVE_EVAS -# include -#endif - -# include "Ecore_Data.h" +#include "Evas_Data.h" +#include "Ecore_Data.h" #include "eina_bench.h" #include "eina_array.h" #include "eina_list.h" #include "eina_inlist.h" +#include "eina_main.h" typedef struct _Eina_Bench_Object Eina_Bench_Object; struct _Eina_Bench_Object @@ -557,8 +555,6 @@ eina_bench_gptrarray_4evas_render(int request) } #endif -#ifdef EINA_BENCH_HAVE_EVAS -#if 0 static void eina_bench_evas_list_4evas_render(int request) { @@ -568,8 +564,6 @@ eina_bench_evas_list_4evas_render(int request) int i; int j; - evas_init(); - for (i = 0; i < 1000; ++i) { for (j = 0; j < request; ++j) @@ -624,11 +618,7 @@ eina_bench_evas_list_4evas_render(int request) free(evas_list_data(list)); list = evas_list_remove_list(list, list); } - - evas_shutdown(); } -#endif -#endif static void _eina_ecore_for_each_remove(void *value, void *user_data) @@ -701,11 +691,7 @@ void eina_bench_array(Eina_Benchmark *bench) eina_benchmark_register(bench, "glist", EINA_BENCHMARK(eina_bench_glist_4evas_render), 200, 4000, 100); eina_benchmark_register(bench, "gptrarray", EINA_BENCHMARK(eina_bench_gptrarray_4evas_render), 200, 4000, 100); #endif -#ifdef EINA_BENCH_HAVE_EVAS -#if 0 eina_benchmark_register(bench, "evas", EINA_BENCHMARK(eina_bench_evas_list_4evas_render), 200, 4000, 100); -#endif -#endif eina_benchmark_register(bench, "ecore", EINA_BENCHMARK(eina_bench_ecore_list_4evas_render), 200, 1000, 100); } diff --git a/legacy/eina/src/tests/eina_bench_hash.c b/legacy/eina/src/tests/eina_bench_hash.c index 66c00a232f..686ab924c2 100644 --- a/legacy/eina/src/tests/eina_bench_hash.c +++ b/legacy/eina/src/tests/eina_bench_hash.c @@ -29,11 +29,8 @@ # include #endif -#ifdef EINA_BENCH_HAVE_EVAS -# include -#endif - -# include +#include "Evas_Data.h" +#include "Ecore_Data.h" #include "eina_hash.h" #include "eina_array.h" @@ -278,8 +275,6 @@ eina_bench_lookup_ghash(int request) } #endif -#ifdef EINA_BENCH_HAVE_EVAS -#if 0 static void eina_bench_lookup_evas(int request) { @@ -298,7 +293,7 @@ eina_bench_lookup_evas(int request) tmp_val = malloc(sizeof (int)); - if (!tmp_key || !tmp_val) continue ; + if (!tmp_val) continue ; eina_convert_itoa(i, tmp_key); *tmp_val = i; @@ -327,8 +322,6 @@ eina_bench_lookup_evas(int request) eina_array_free(array); } -#endif -#endif typedef struct _Eina_Bench_Ecore Eina_Bench_Ecore; struct _Eina_Bench_Ecore @@ -386,10 +379,6 @@ void eina_bench_hash(Eina_Benchmark *bench) #ifdef EINA_BENCH_HAVE_GLIB eina_benchmark_register(bench, "ghash-lookup", EINA_BENCHMARK(eina_bench_lookup_ghash), 10, 3000, 10); #endif -#ifdef EINA_BENCH_HAVE_EVAS -#if 0 eina_benchmark_register(bench, "evas-lookup", EINA_BENCHMARK(eina_bench_lookup_evas), 10, 3000, 10); -#endif -#endif eina_benchmark_register(bench, "ecore-lookup", EINA_BENCHMARK(eina_bench_lookup_ecore), 10, 3000, 10); } diff --git a/legacy/eina/src/tests/eina_bench_sort.c b/legacy/eina/src/tests/eina_bench_sort.c index 65caf2eaf4..45e4e108f4 100644 --- a/legacy/eina/src/tests/eina_bench_sort.c +++ b/legacy/eina/src/tests/eina_bench_sort.c @@ -27,14 +27,13 @@ # include #endif -#ifdef EINA_BENCH_HAVE_EVAS -# include -#endif - -# include "Ecore_Data.h" +#include "Evas_Data.h" +#include "Ecore_Data.h" #include "eina_bench.h" -#include "Eina.h" +#include "eina_convert.h" +#include "eina_list.h" +#include "eina_main.h" static int _eina_cmp_str(const char *a, const char *b) @@ -72,16 +71,12 @@ eina_bench_sort_eina(int request) eina_shutdown(); } -#ifdef EINA_BENCH_HAVE_EVAS -#if 0 static void eina_bench_sort_evas(int request) { Evas_List *list = NULL; int i; - evas_init(); - srand(time(NULL)); for (i = 0; i < request; ++i) @@ -100,11 +95,7 @@ eina_bench_sort_evas(int request) free(evas_list_data(list)); list = evas_list_remove_list(list, list); } - - evas_shutdown(); } -#endif -#endif #ifdef EINA_BENCH_HAVE_GLIB static void @@ -212,11 +203,7 @@ void eina_bench_sort(Eina_Benchmark *bench) eina_benchmark_register(bench, "ecore", EINA_BENCHMARK(eina_bench_sort_ecore_default), 10, 10000, 100); eina_benchmark_register(bench, "ecore-merge", EINA_BENCHMARK(eina_bench_sort_ecore_merge), 10, 10000, 100); eina_benchmark_register(bench, "ecore-heap", EINA_BENCHMARK(eina_bench_sort_ecore_heap), 10, 10000, 100); -#ifdef EINA_BENCH_HAVE_EVAS -#if 0 eina_benchmark_register(bench, "evas", EINA_BENCHMARK(eina_bench_sort_evas), 10, 10000, 100); -#endif -#endif } diff --git a/legacy/eina/src/tests/eina_bench_stringshare.c b/legacy/eina/src/tests/eina_bench_stringshare.c index acea0435e1..f65cc7628a 100644 --- a/legacy/eina/src/tests/eina_bench_stringshare.c +++ b/legacy/eina/src/tests/eina_bench_stringshare.c @@ -28,15 +28,13 @@ # include #endif -#ifdef EINA_BENCH_HAVE_EVAS -# include -#endif - -# include "Ecore_Data.h" +#include "Evas_Data.h" +#include "Ecore_Data.h" #include "eina_stringshare.h" #include "eina_bench.h" #include "eina_convert.h" +#include "eina_main.h" static void eina_bench_stringshare_job(int request) @@ -102,8 +100,6 @@ eina_bench_stringchunk_job(int request) } #endif -#ifdef EINA_BENCH_HAVE_EVAS -#if 0 static void eina_bench_evas_job(int request) { @@ -111,9 +107,6 @@ eina_bench_evas_job(int request) unsigned int j; int i; - evas_init(); -/* evas_stringshare_init(); */ - for (i = 0; i < request; ++i) { char build[64] = "string_"; @@ -132,12 +125,7 @@ eina_bench_evas_job(int request) eina_convert_xtoa(rand() % request, build + 7); tmp = evas_stringshare_add(build); } - -/* evas_stringshare_shutdown(); */ - evas_shutdown(); } -#endif -#endif static void eina_bench_ecore_job(int request) @@ -176,10 +164,6 @@ void eina_bench_stringshare(Eina_Benchmark *bench) #ifdef EINA_BENCH_HAVE_GLIB eina_benchmark_register(bench, "stringchunk (glib)", EINA_BENCHMARK(eina_bench_stringchunk_job), 100, 20100, 500); #endif -#ifdef EINA_BENCH_HAVE_EVAS -#if 0 eina_benchmark_register(bench, "stringshare (evas)", EINA_BENCHMARK(eina_bench_evas_job), 100, 20100, 500); -#endif -#endif eina_benchmark_register(bench, "stringshare (ecore)", EINA_BENCHMARK(eina_bench_ecore_job), 100, 20100, 500); } diff --git a/legacy/eina/src/tests/eina_bench_stringshare_e17.c b/legacy/eina/src/tests/eina_bench_stringshare_e17.c index d7146f47ca..be62cf64e2 100644 --- a/legacy/eina/src/tests/eina_bench_stringshare_e17.c +++ b/legacy/eina/src/tests/eina_bench_stringshare_e17.c @@ -28,13 +28,8 @@ # include #endif -#ifdef EINA_BENCH_HAVE_EVAS -# include -#endif - -#ifdef EINA_BENCH_HAVE_ECORE -# include -#endif +#include "Evas_Data.h" +#include "Ecore_Data.h" #include "Eina.h" @@ -60,17 +55,14 @@ static Eina_Stringshare_Test eina_str = { eina_shutdown }; -#ifdef EINA_BENCH_HAVE_EVAS static Eina_Stringshare_Test evas_str = { "evas", - evas_init, + evas_stringshare_init, evas_stringshare_add, evas_stringshare_del, - evas_shutdown + evas_stringshare_shutdown }; -#endif -#ifdef EINA_BENCH_HAVE_ECORE static Eina_Stringshare_Test ecore_str = { "ecore", ecore_string_init, @@ -78,16 +70,11 @@ static Eina_Stringshare_Test ecore_str = { ecore_string_release, ecore_string_shutdown }; -#endif static Eina_Stringshare_Test* str[] = { &eina_str, -#ifdef EINA_BENCH_HAVE_EVAS &evas_str, -#endif -#ifdef EINA_BENCH_HAVE_ECORE &ecore_str, -#endif NULL }; diff --git a/legacy/eina/src/tests/evas_hash.c b/legacy/eina/src/tests/evas_hash.c new file mode 100644 index 0000000000..42892c04ea --- /dev/null +++ b/legacy/eina/src/tests/evas_hash.c @@ -0,0 +1,498 @@ +/* + * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include + +#include "Evas_Data.h" + +typedef struct _Evas_Hash_El Evas_Hash_El; + +struct _Evas_Hash_El +{ + Evas_Object_List _list_data; + const char *key; + void *data; +}; + +static inline int _evas_hash_gen(const char *key); + +static int _evas_hash_alloc_error = 0; + +static inline int +_evas_hash_gen(const char *key) +{ + unsigned int hash_num = 5381; + const unsigned char *ptr; + + if (!key) return 0; + for (ptr = (unsigned char *)key; *ptr; ptr++) + hash_num = (hash_num * 33) ^ *ptr; + + hash_num &= 0xff; + return (int)hash_num; +} + +/** + * @defgroup Evas_Hash_Data Hash Data Functions + * + * Functions that add, access or remove data from hashes. + * + * The following example shows how to add and then access data in a + * hash table: + * @code + * Evas_Hash *hash = NULL; + * extern void *my_data; + * + * hash = evas_hash_add(hash, "My Data", my_data); + * if (evas_hash_alloc_error()) + * { + * fprintf(stderr, "ERROR: Memory is low. Hash allocation failed.\n"); + * exit(-1); + * } + * if (evas_hash_find(hash, "My Data") == my_data) + * { + * printf("My Data inserted and successfully found.\n"); + * } + * @endcode + * + * What follows is another example, showing how the @ref evas_hash_del + * function is used: + * @code + * extern Evas_Hash *hash; + * extern void *data; + * + * printf("Insert some data...\n"); + * hash = evas_hash_add(hash, "My Data", my_data); + * printf("Removing by key...\n"); + * hash = evas_hash_del(hash, "My Data", NULL); + * printf("Insert some more data as a NULL key...\n"); + * hash = evas_hash_add(hash, NULL, my_data); + * printf("Removing by data as a NULL key...\n"); + * hash = evas_hash_del(hash, NULL, my_data); + * @endcode + */ + +/** + * Adds an entry to the given hash table. + * + * @p key is expected to be a unique string within the hash table. + * Otherwise, you cannot be sure which inserted data pointer will be + * accessed with @ref evas_hash_find , and removed with + * @ref evas_hash_del . + * + * Key strings are case sensitive. + * + * @ref evas_hash_alloc_error should be used to determine if an + * allocation error occurred during this function. + * + * @param hash The given hash table. Can be @c NULL, in which case a + * new hash table is allocated and returned. + * @param key A unique string. Can be @c NULL. + * @param data Data to associate with the string given by @p key. + * @return Either the given hash table, or if the given value for @p + * hash is @c NULL, then a new one. @c NULL will be returned + * if memory could not be allocated for a new table. + * @ingroup Evas_Hash_Data + */ +EAPI Evas_Hash * +evas_hash_add(Evas_Hash *hash, const char *key, const void *data) +{ + int hash_num; + Evas_Hash_El *el; + + if ((!key) || (!data)) return hash; + _evas_hash_alloc_error = 0; + if (!hash) + { + hash = calloc(1, sizeof(struct _Evas_Hash)); + if (!hash) + { + _evas_hash_alloc_error = 1; + return NULL; + } + } + if (!(el = malloc(sizeof(struct _Evas_Hash_El) + strlen(key) + 1))) + { + if (hash->population <= 0) + { + free(hash); + hash = NULL; + } + _evas_hash_alloc_error = 1; + return hash; + }; + el->key = ((char *)el) + sizeof(struct _Evas_Hash_El); + strcpy((char *) el->key, key); + el->data = (void *)data; + hash_num = _evas_hash_gen(key); + hash->buckets[hash_num] = evas_object_list_prepend(hash->buckets[hash_num], el); + hash->population++; + return hash; +} + +/** + * Adds an entry to the given hash table and does not duplicate the string key. + * + * @p key is expected to be a unique string within the hash table. + * Otherwise, you cannot be sure which inserted data pointer will be + * accessed with @ref evas_hash_find , and removed with + * @ref evas_hash_del . This call does not make a copy of the key so it must + * be a string constant or stored elsewhere (in the object being added) etc. + * + * Key strings are case sensitive. + * + * @ref evas_hash_alloc_error should be used to determine if an + * allocation error occurred during this function. + * + * @param hash The given hash table. Can be @c NULL, in which case a + * new hash table is allocated and returned. + * @param key A unique string. Can be @c NULL. + * @param data Data to associate with the string given by @p key. + * @return Either the given hash table, or if the given value for @p + * hash is @c NULL, then a new one. @c NULL will be returned + * if memory could not be allocated for a new table. + * @ingroup Evas_Hash_Data + */ +EAPI Evas_Hash * +evas_hash_direct_add(Evas_Hash *hash, const char *key, const void *data) +{ + int hash_num; + Evas_Hash_El *el; + + if ((!key) || (!data)) return hash; + _evas_hash_alloc_error = 0; + if (!hash) + { + hash = calloc(1, sizeof(struct _Evas_Hash)); + if (!hash) + { + _evas_hash_alloc_error = 1; + return NULL; + } + } + if (!(el = malloc(sizeof(struct _Evas_Hash_El)))) + { + if (hash->population <= 0) + { + free(hash); + hash = NULL; + } + _evas_hash_alloc_error = 1; + return hash; + }; + el->key = key; + el->data = (void *)data; + hash_num = _evas_hash_gen(key); + hash->buckets[hash_num] = evas_object_list_prepend(hash->buckets[hash_num], el); + hash->population++; + return hash; +} + +/** + * Removes the entry identified by @p key or @p data from the given + * hash table. + * + * If @p key is @c NULL, then @p data is used to find a match to + * remove. + * + * @param hash The given hash table. + * @param key The key string. Can be @c NULL. + * @param data The data pointer to remove if @p key is @c NULL. + * Otherwise, not required and can be @c NULL. + * @return The modified hash table. If there are no entries left, the + * hash table will be freed and @c NULL will be returned. + * @ingroup Evas_Hash_Data + */ +EAPI Evas_Hash * +evas_hash_del(Evas_Hash *hash, const char *key, const void *data) +{ + int hash_num; + Evas_Hash_El *el; + Evas_Object_List *l; + + if (!hash) return NULL; + if (!key) + { + for (hash_num = 0; hash_num < 256; hash_num++) + { + for (l = hash->buckets[hash_num]; l; l = l->next) + { + el = (Evas_Hash_El *)l; + if (el->data == data) + { + hash->buckets[hash_num] = evas_object_list_remove(hash->buckets[hash_num], el); + free(el); + hash->population--; + if (hash->population <= 0) + { + free(hash); + hash = NULL; + } + return hash; + } + } + } + } + else + { + hash_num = _evas_hash_gen(key); + for (l = hash->buckets[hash_num]; l; l = l->next) + { + el = (Evas_Hash_El *)l; + if (!strcmp(el->key, key)) + { + if ((!data) || (el->data == data)) + { + hash->buckets[hash_num] = evas_object_list_remove(hash->buckets[hash_num], el); + free(el); + hash->population--; + if (hash->population <= 0) + { + free(hash); + hash = NULL; + } + return hash; + } + } + } + } + return hash; +} + +/** + * Retrieves a specific entry in the given hash table. + * @param hash The given hash table. + * @param key The key string of the entry to find. + * @return The data pointer for the stored entry, or @c NULL if not + * found. + * @ingroup Evas_Hash_Data + */ +EAPI void * +evas_hash_find(const Evas_Hash *hash, const char *key) +{ + int hash_num; + Evas_Hash_El *el; + Evas_Object_List *l; + + _evas_hash_alloc_error = 0; + if ((!hash) || (!key)) return NULL; + hash_num = _evas_hash_gen(key); + for (l = hash->buckets[hash_num]; l; l = l->next) + { + el = (Evas_Hash_El *)l; + if (!strcmp(el->key, key)) + { + if (l != hash->buckets[hash_num]) + { + Evas_Object_List *bucket; + + bucket = hash->buckets[hash_num]; + bucket = evas_object_list_remove(bucket, el); + bucket = evas_object_list_prepend(bucket, el); + ((Evas_Hash *)hash)->buckets[hash_num] = bucket; + } + return el->data; + } + } + return NULL; +} + +/** + * Modifies the entry pointer at the specified key and returns the old entry + * @param hash The given hash table. + * @param key The key string of the entry to modify. + * @param data The data to replace the old entry, if it exists. + * @return The data pointer for the old stored entry, or @c NULL if not + * found. If an existing entry is not found, nothing is added to the + * hash. + * @ingroup Evas_Hash_Data + */ +EAPI void * +evas_hash_modify(Evas_Hash *hash, const char *key, const void *data) +{ + int hash_num; + Evas_Hash_El *el; + Evas_Object_List *l; + + _evas_hash_alloc_error = 0; + if (!hash) return NULL; + hash_num = _evas_hash_gen(key); + for (l = hash->buckets[hash_num]; l; l = l->next) + { + el = (Evas_Hash_El *)l; + if ((key) && (!strcmp(el->key, key))) + { + void *old_data; + + if (l != hash->buckets[hash_num]) + { + hash->buckets[hash_num] = evas_object_list_remove(hash->buckets[hash_num], el); + hash->buckets[hash_num] = evas_object_list_prepend(hash->buckets[hash_num], el); + } + old_data = el->data; + el->data = (void *) data; + return old_data; + } + } + return NULL; +} + +/** + * @defgroup Evas_Hash_General_Group Hash General Functions + * + * Miscellaneous functions that operate on hash objects. + */ + +/** + * Retrieves the number of buckets available in the given hash table. + * @param hash The given hash table. + * @return @c 256 if @p hash is not @c NULL. @c 0 otherwise. + * @ingroup Evas_Hash_General_Group + */ +EAPI int +evas_hash_size(const Evas_Hash *hash) +{ + if (!hash) return 0; + return 256; +} + +/** + * @todo Complete polishing documentation for evas_hash.c. The + * functions' docs may be grouped, but they need some simplification. + */ + +/** + * Free an entire hash table + * @param hash The hash table to be freed + * + * This function frees up all the memory allocated to storing the specified + * hash tale pointed to by @p hash. Any entries in the table that the program + * has no more pointers for elsewhere may now be lost, so this should only be + * called if the program has lready freed any allocated data in the hash table + * or has the pointers for data in teh table stored elswehere as well. + * + * Example: + * @code + * extern Evas_Hash *hash; + * + * evas_hash_free(hash); + * hash = NULL; + * @endcode + * @ingroup Evas_Hash_General_Group + */ +EAPI void +evas_hash_free(Evas_Hash *hash) +{ + int i, size; + + if (!hash) return; + size = evas_hash_size(hash); + for (i = 0; i < size; i++) + { + while (hash->buckets[i]) + { + Evas_Hash_El *el; + + el = (Evas_Hash_El *)hash->buckets[i]; + hash->buckets[i] = evas_object_list_remove(hash->buckets[i], el); + free(el); + } + } + free(hash); +} + +/** + * Call a function on every member stored in the hash table + * @param hash The hash table whose members will be walked + * @param func The function to call on each parameter + * @param fdata The data pointer to pass to the function being called + * + * This function goes through every entry in the hash table @p hash and calls + * the function @p func on each member. The function should NOT modify the + * hash table contents if it returns 1. IF the hash table contents are + * modified by this function or the function wishes to stop processing it must + * return 0, otherwise return 1 to keep processing. + * + * Example: + * @code + * extern Evas_Hash *hash; + * + * Evas_Bool hash_fn(Evas_Hash *hash, const char *key, void *data, void *fdata) + * { + * printf("Func data: %s, Hash entry: %s / %p\n", fdata, key, data); + * return 1; + * } + * + * int main(int argc, char **argv) + * { + * char *hash_fn_data; + * + * hash_fn_data = strdup("Hello World"); + * evas_hash_foreach(hash, hash_fn, hash_fn_data); + * free(hash_fn_data); + * } + * @endcode + * @ingroup Evas_Hash_General_Group + */ +EAPI void +evas_hash_foreach(const Evas_Hash *hash, Evas_Bool (*func) (const Evas_Hash *hash, const char *key, void *data, void *fdata), const void *fdata) +{ + int i, size; + + if (!hash) return; + size = evas_hash_size(hash); + for (i = 0; i < size; i++) + { + Evas_Object_List *l, *next_l; + + for (l = hash->buckets[i]; l;) + { + Evas_Hash_El *el; + + next_l = l->next; + el = (Evas_Hash_El *)l; + if (!func(hash, el->key, el->data, (void *)fdata)) return; + l = next_l; + } + } +} + +/** + * Return memory allocation failure flag after an function requiring 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 fail during evas_hash_add() calls. If they do, 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 + * Evas_Hash *hash = NULL; + * extern void *my_data; + * + * hash = evas_hash_add(hash, "My Data", my_data); + * if (evas_hash_alloc_error()) + * { + * fprintf(stderr, "ERROR: Memory is low. Hash allocation failed.\n"); + * exit(-1); + * } + * if (evas_hash_find(hash, "My Data") == my_data) + * { + * printf("My Data inserted and successfully found.\n"); + * } + * @endcode + * @ingroup Evas_Hash_General_Group + */ +EAPI int +evas_hash_alloc_error(void) +{ + return _evas_hash_alloc_error; +} diff --git a/legacy/eina/src/tests/evas_list.c b/legacy/eina/src/tests/evas_list.c new file mode 100644 index 0000000000..926a495455 --- /dev/null +++ b/legacy/eina/src/tests/evas_list.c @@ -0,0 +1,1031 @@ +/* + * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include + +#include "Evas_Data.h" +#include + +typedef struct _Evas_List_Accounting Evas_List_Accounting; + +struct _Evas_List_Accounting +{ + Evas_List *last; + int count; +}; + +static int _evas_list_alloc_error = 0; + +static Evas_Mempool _evas_list_mempool = +{ + sizeof(Evas_List), + 320, + 0, NULL, NULL +}; +static Evas_Mempool _evas_list_accounting_mempool = +{ + sizeof(Evas_List_Accounting), + 80, + 0, NULL, NULL +}; + +/** + * @defgroup Evas_List_Data_Group Linked List Creation Functions + * + * Functions that add data to an Evas_List. + */ + +/** + * Appends the given data to the given linked list. + * + * The following example code demonstrates how to ensure that the + * given data has been successfully appended. + * + * @code + * Evas_List *list = NULL; + * extern void *my_data; + * + * list = evas_list_append(list, my_data); + * if (evas_list_alloc_error()) + * { + * fprintf(stderr, "ERROR: Memory is low. List allocation failed.\n"); + * exit(-1); + * } + * @endcode + * + * @param list The given list. If @c NULL is given, then a new list + * is created. + * @param data The data to append. + * @return A new list pointer that should be used in place of the one + * given to this function if successful. Otherwise, the old + * pointer is returned. + * @ingroup Evas_List_Data_Group + */ +EAPI Evas_List * +evas_list_append(Evas_List *list, const void *data) +{ + Evas_List *l, *new_l; + + _evas_list_alloc_error = 0; + new_l = evas_mempool_malloc(&_evas_list_mempool, sizeof(Evas_List)); + if (!new_l) + { + _evas_list_alloc_error = 1; + return list; + } + new_l->next = NULL; + new_l->data = (void *)data; + if (!list) + { + new_l->prev = NULL; + new_l->accounting = evas_mempool_malloc(&_evas_list_accounting_mempool, sizeof(Evas_List_Accounting)); + if (!new_l->accounting) + { + _evas_list_alloc_error = 1; + evas_mempool_free(&_evas_list_mempool, new_l); + return list; + } + new_l->accounting->last = new_l; + new_l->accounting->count = 1; + return new_l; + } + l = list->accounting->last; + l->next = new_l; + new_l->prev = l; + new_l->accounting = list->accounting; + list->accounting->last = new_l; + list->accounting->count++; + return list; +} + +/** + * Prepends the given data to the given linked list. + * + * The following example code demonstrates how to ensure that the + * given data has been successfully prepended. + * + * Example: + * @code + * Evas_List *list = NULL; + * extern void *my_data; + * + * list = evas_list_prepend(list, my_data); + * if (evas_list_alloc_error()) + * { + * fprintf(stderr, "ERROR: Memory is low. List allocation failed.\n"); + * exit(-1); + * } + * @endcode + * + * @param list The given list. + * @param data The given data. + * @return A new list pointer that should be used in place of the one + * given to this function, if successful. Otherwise, the old + * pointer is returned. + * @ingroup Evas_List_Data_Group + */ +EAPI Evas_List * +evas_list_prepend(Evas_List *list, const void *data) +{ + Evas_List *new_l; + + _evas_list_alloc_error = 0; + new_l = evas_mempool_malloc(&_evas_list_mempool, sizeof(Evas_List)); + if (!new_l) + { + _evas_list_alloc_error = 1; + return list; + } + new_l->prev = NULL; + new_l->data = (void *)data; + if (!list) + { + new_l->next = NULL; + new_l->accounting = evas_mempool_malloc(&_evas_list_accounting_mempool, sizeof(Evas_List_Accounting)); + if (!new_l->accounting) + { + _evas_list_alloc_error = 1; + evas_mempool_free(&_evas_list_mempool, new_l); + return list; + } + new_l->accounting->last = new_l; + new_l->accounting->count = 1; + return new_l; + } + new_l->next = list; + list->prev = new_l; + new_l->accounting = list->accounting; + list->accounting->count++; + return new_l; +} + +/** + * Inserts the given data into the given linked list after the specified data. + * + * If @p relative is not in the list, @p data is appended to the end of the + * list. If there are multiple instances of @p relative in the list, + * @p data is inserted after the first instance. + * + * The following example code demonstrates how to ensure that the + * given data has been successfully inserted. + * + * @code + * Evas_List *list = NULL; + * extern void *my_data; + * extern void *relative_member; + * + * list = evas_list_append(list, relative_member); + * if (evas_list_alloc_error()) + * { + * fprintf(stderr, "ERROR: Memory is low. List allocation failed.\n"); + * exit(-1); + * } + * list = evas_list_append_relative(list, my_data, relative_member); + * if (evas_list_alloc_error()) + * { + * fprintf(stderr, "ERROR: Memory is low. List allocation failed.\n"); + * exit(-1); + * } + * @endcode + * + * @param list The given linked list. + * @param data The given data. + * @param relative The data to insert after. + * @return A new list pointer that should be used in place of the one + * given to this function if successful. Otherwise, the old pointer + * is returned. + * @ingroup Evas_List_Data_Group + */ +EAPI Evas_List * +evas_list_append_relative(Evas_List *list, const void *data, const void *relative) +{ + Evas_List *l; + + for (l = list; l; l = l->next) + { + if (l->data == relative) + return evas_list_append_relative_list(list, data, l); + } + return evas_list_append(list, data); +} + +EAPI Evas_List * +evas_list_append_relative_list(Evas_List *list, const void *data, Evas_List *relative) +{ + Evas_List *new_l; + + if ((!list) || (!relative)) return evas_list_append(list, data); + _evas_list_alloc_error = 0; + new_l = evas_mempool_malloc(&_evas_list_mempool, sizeof(Evas_List)); + if (!new_l) + { + _evas_list_alloc_error = 1; + return list; + } + 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 = new_l; + new_l->prev = relative; + new_l->accounting = list->accounting; + list->accounting->count++; + if (!new_l->next) + new_l->accounting->last = new_l; + return list; +} + +/** + * Prepend a data pointer to a linked list before the memeber specified + * @param list The list handle to prepend @p data too + * @param data The data pointer to prepend to list @p list before @p relative + * @param relative The data pointer before which to insert @p data + * @return A new list handle to replace the old one + + * Inserts the given data into the given linked list before the member + * specified. + * + * If @p relative is not in the list, @p data is prepended to the + * start of the list. If there are multiple instances of @p relative + * in the list, @p data is inserted before the first instance. + * + * The following code example demonstrates how to ensure that the + * given data has been successfully inserted. + * + * @code + * Evas_List *list = NULL; + * extern void *my_data; + * extern void *relative_member; + * + * list = evas_list_append(list, relative_member); + * if (evas_list_alloc_error()) + * { + * fprintf(stderr, "ERROR: Memory is low. List allocation failed.\n"); + * exit(-1); + * } + * list = evas_list_prepend_relative(list, my_data, relative_member); + * if (evas_list_alloc_error()) + * { + * fprintf(stderr, "ERROR: Memory is low. List allocation failed.\n"); + * exit(-1); + * } + * @endcode + * + * @param list The given linked list. + * @param data The given data. + * @param relative The data to insert before. + * @return A new list pointer that should be used in place of the one + * given to this function if successful. Otherwise the old pointer + * is returned. + * @ingroup Evas_List_Data_Group + */ +EAPI Evas_List * +evas_list_prepend_relative(Evas_List *list, const void *data, const void *relative) +{ + Evas_List *l; + + _evas_list_alloc_error = 0; + for (l = list; l; l = l->next) + { + if (l->data == relative) + return evas_list_prepend_relative_list(list, data, l); + } + return evas_list_prepend(list, data); +} + +EAPI Evas_List * +evas_list_prepend_relative_list(Evas_List *list, const void *data, Evas_List *relative) +{ + Evas_List *new_l; + + if ((!list) || (!relative)) return evas_list_prepend(list, data); + _evas_list_alloc_error = 0; + new_l = evas_mempool_malloc(&_evas_list_mempool, sizeof(Evas_List)); + if (!new_l) + { + _evas_list_alloc_error = 1; + return list; + } + new_l->data = (void *)data; + new_l->prev = relative->prev; + new_l->next = relative; + if (relative->prev) relative->prev->next = new_l; + relative->prev = new_l; + new_l->accounting = list->accounting; + list->accounting->count++; + if (new_l->prev) + return list; + return new_l; +} + +/** + * @defgroup Evas_List_Remove_Group Linked List Remove Functions + * + * Functions that remove data from linked lists. + */ + +/** + * Removes the first instance of the specified data from the given list. + * + * If the specified data is not in the given list, nothing is done. + * + * @param list The given list. + * @param data The specified data. + * @return A new list pointer that should be used in place of the one + * passed to this functions. + * @ingroup Evas_List_Remove_Group + */ +EAPI Evas_List * +evas_list_remove(Evas_List *list, const void *data) +{ + Evas_List *l; + + for (l = list; l; l = l->next) + { + if (l->data == data) + return evas_list_remove_list(list, l); + } + return list; +} + +/** + * Removes the specified data + * + * Remove a specified member from a list + * @param list The list handle to remove @p remove_list from + * @param remove_list The list node which is to be removed + * @return A new list handle to replace the old one + * + * Calling this function takes the list node @p remove_list and removes it + * from the list @p list, freeing the list node structure @p remove_list. + * + * Example: + * @code + * extern Evas_List *list; + * Evas_List *l; + * extern void *my_data; + * + * for (l = list; l; l= l->next) + * { + * if (l->data == my_data) + * { + * list = evas_list_remove_list(list, l); + * break; + * } + * } + * @endcode + * @ingroup Evas_List_Remove_Group + */ +EAPI Evas_List * +evas_list_remove_list(Evas_List *list, Evas_List *remove_list) +{ + Evas_List *return_l; + + if (!list) return NULL; + if (!remove_list) return list; + if (remove_list->next) remove_list->next->prev = remove_list->prev; + if (remove_list->prev) + { + remove_list->prev->next = remove_list->next; + return_l = list; + } + else + 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) + evas_mempool_free(&_evas_list_accounting_mempool, list->accounting); + evas_mempool_free(&_evas_list_mempool, remove_list); + return return_l; +} + +/** + * Moves the specified data to the head of the list + * + * Move a specified member to the head of the list + * @param list The list handle to move @p inside + * @param move_list The list node which is to be moved + * @return A new list handle to replace the old one + * + * Calling this function takes the list node @p move_list and moves it + * to the front of the @p list. + * + * Example: + * @code + * extern Evas_List *list; + * Evas_List *l; + * extern void *my_data; + * + * for (l = list; l; l= l->next) + * { + * if (l->data == my_data) + * { + * list = evas_list_promote_list(list, l); + * break; + * } + * } + * @endcode + * @ingroup Evas_List_Promote_Group + */ +EAPI Evas_List * +evas_list_promote_list(Evas_List *list, Evas_List *move_list) +{ + Evas_List *return_l; + + if (!list) return NULL; + if (!move_list) return list; + 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; + 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; + return move_list; +} + + + +/** + * @defgroup Evas_List_Find_Group Linked List Find Functions + * + * Functions that find specified data in a linked list. + */ + +/** + * Find a member of a list and return the member + * @param list The list handle to search for @p data + * @param data The data pointer to find in the list @p list + * @return The found member data pointer + * + * A call to this function will search the list @p list from beginning to end + * for the first member whose data pointer is @p data. If it is found, @p data + * will be returned, otherwise NULL will be returned. + * + * Example: + * @code + * extern Evas_List *list; + * extern void *my_data; + * + * if (evas_list_find(list, my_data) == my_data) + * { + * printf("Found member %p\n", my_data); + * } + * @endcode + * @ingroup Evas_List_Find_Group + */ +EAPI void * +evas_list_find(const Evas_List *list, const void *data) +{ + const Evas_List *l; + + for (l = list; l; l = l->next) + { + if (l->data == data) return (void *)data; + } + return NULL; +} + +/** + * Find a member of a list and return the list node containing that member + * @param list The list handle to search for @p data + * @param data The data pointer to find in the list @p list + * @return The found members list node + * + * A call to this function will search the list @p list from beginning to end + * for the first member whose data pointer is @p data. If it is found, the + * list node containing the specified member will be returned, otherwise NULL + * will be returned. + * + * Example: + * @code + * extern Evas_List *list; + * extern void *my_data; + * Evas_List *found_node; + * + * found_node = evas_list_find_list(list, my_data); + * if (found_node) + * { + * printf("Found member %p\n", found_node->data); + * } + * @endcode + * @ingroup Evas_List_Find_Group + */ +EAPI Evas_List * +evas_list_find_list(const Evas_List *list, const void *data) +{ + const Evas_List *l; + + for (l = list; l; l = l->next) + { + if (l->data == data) return (Evas_List *)l; + } + return NULL; +} + +/** + * Free an entire list and all the nodes, ignoring the data contained + * @param list The list to free + * @return A NULL pointer + * + * This function will free all the list nodes in list specified by @p list. + * + * Example: + * @code + * extern Evas_List *list; + * + * list = evas_list_free(list); + * @endcode + * @ingroup Evas_List_Remove_Group + */ +EAPI Evas_List * +evas_list_free(Evas_List *list) +{ + Evas_List *l, *free_l; + + if (!list) return NULL; + evas_mempool_free(&_evas_list_accounting_mempool, list->accounting); + for (l = list; l;) + { + free_l = l; + l = l->next; + evas_mempool_free(&_evas_list_mempool, free_l); + } + return NULL; +} + +/** + * @defgroup Evas_List_Traverse_Group Linked List Traverse Functions + * + * Functions that you can use to traverse a linked list. + */ + +/** + * Get the last list node in the list + * @param list The list to get the last list node from + * @return The last list node in the list @p list + * + * This function will return the last list node in the list (or NULL if the + * list is empty). + * + * NB: This is a order-1 operation (it takes the same short time regardless of + * the length of the list). + * + * Example: + * @code + * extern Evas_List *list; + * Evas_List *last, *l; + * + * last = evas_list_last(list); + * printf("The list in reverse:\n"); + * for (l = last; l; l = l->prev) + * { + * printf("%p\n", l->data); + * } + * @endcode + * @ingroup Evas_List_Traverse_Group + */ +EAPI Evas_List * +evas_list_last(const Evas_List *list) +{ + if (!list) return NULL; + return list->accounting->last; +} + +/** + * Get the next list node after the specified list node + * @param list The list node to get the next list node from + * @return The next list node, or NULL if no next list node exists + * + * This function returns the next list node after the current one. It is + * equivalent to list->next. + * + * Example: + * @code + * extern Evas_List *list; + * Evas_List *l; + * + * printf("The list:\n"); + * for (l = list; l; l = evas_list_next(l)) + * { + * printf("%p\n", l->data); + * } + * @endcode + * @ingroup Evas_List_Traverse_Group + */ +EAPI Evas_List * +evas_list_next(const Evas_List *list) +{ + if (!list) return NULL; + return list->next; +} + +/** + * Get the previous list node before the specified list node + * @param list The list node to get the previous list node from + * @return The previous list node, or NULL if no previous list node exists + * + * This function returns the previous list node before the current one. It is + * equivalent to list->prev. + * + * Example: + * @code + * extern Evas_List *list; + * Evas_List *last, *l; + * + * last = evas_list_last(list); + * printf("The list in reverse:\n"); + * for (l = last; l; l = evas_list_prev(l)) + * { + * printf("%p\n", l->data); + * } + * @endcode + * @ingroup Evas_List_Traverse_Group + */ +EAPI Evas_List * +evas_list_prev(const Evas_List *list) +{ + if (!list) return NULL; + return list->prev; +} + +/** + * @defgroup Evas_List_General_Group Linked List General Functions + * + * Miscellaneous functions that work on linked lists. + */ + +/** + * Get the list node data member + * @param list The list node to get the data member of + * @return The data member from the list node @p list + * + * This function returns the data member of the specified list node @p list. + * It is equivalent to list->data. + * + * Example: + * @code + * extern Evas_List *list; + * Evas_List *l; + * + * printf("The list:\n"); + * for (l = list; l; l = evas_list_next(l)) + * { + * printf("%p\n", evas_list_data(l)); + * } + * @endcode + * @ingroup Evas_List_General_Group + */ +EAPI void * +evas_list_data(const Evas_List *list) +{ + if (!list) return NULL; + return list->data; +} + +/** + * Get the count of the number of items in a list + * @param list The list whose count to return + * @return The number of members in the list @p list + * + * This function returns how many members in the specified list: @p list. If + * the list is empty (NULL), 0 is returned. + * + * NB: This is an order-1 operation and takes the same tiem regardless of the + * length of the list. + * + * Example: + * @code + * extern Evas_List *list; + * + * printf("The list has %i members\n", evas_list_count(list)); + * @endcode + * @ingroup Evas_List_General_Group + */ +EAPI int +evas_list_count(const Evas_List *list) +{ + if (!list) return 0; + return list->accounting->count; +} + +/** + * Get the nth member's data pointer in a list + * @param list The list to get member number @p n from + * @param n The number of the element (0 being the first) + * @return The data pointer stored in the specified element + * + * This function returns the data pointer of element number @p n, in the list + * @p list. The first element in the array is element number 0. If the element + * number @p n does not exist, NULL will be returned. + * + * Example: + * @code + * extern Evas_List *list; + * extern int number; + * void *data; + * + * data = evas_list_nth(list, number); + * if (data) + * printf("Element number %i has data %p\n", number, data); + * @endcode + * @ingroup Evas_List_Find_Group + */ +EAPI void * +evas_list_nth(const Evas_List *list, int n) +{ + Evas_List *l; + + l = evas_list_nth_list(list, n); + return l ? l->data : NULL; +} + +/** + * Get the nth member's list node in a list + * @param list The list to get member number @p n from + * @param n The number of the element (0 being the first) + * @return The list node stored in the numbered element + * + * This function returns the list node of element number @p n, in the list + * @p list. The first element in the array is element number 0. If the element + * number @p n does not exist, NULL will be returned. + * + * Example: + * @code + * extern Evas_List *list; + * extern int number; + * Evas_List *nth_list; + * + * nth_list = evas_list_nth_list(list, number); + * if (nth_list) + * printf("Element number %i has data %p\n", number, nth_list->data); + * @endcode + * @ingroup Evas_List_Find_Group + */ +EAPI Evas_List * +evas_list_nth_list(const Evas_List *list, int n) +{ + int i; + const Evas_List *l; + + /* check for non-existing nodes */ + if ((!list) || (n < 0) || + (n > (list->accounting->count - 1))) + return NULL; + + /* if the node is in the 2nd half of the list, search from the end + * else, search from the beginning. + */ + if (n > (list->accounting->count / 2)) + { + for (i = list->accounting->count - 1, + l = list->accounting->last; + l; + l = l->prev, i--) + { + if (i == n) return (Evas_List *)l; + } + } + else + { + for (i = 0, l = list; l; l = l->next, i++) + { + if (i == n) return (Evas_List *)l; + } + } + return NULL; +} + +/** + * @defgroup Evas_List_Ordering_Group Linked List Ordering Functions + * + * Functions that change the ordering of data in a linked list. + */ + +/** + * Reverse all the elements in the list + * @param list The list to reverse + * @return The list after it has been reversed + * + * This takes a list @p list, and reverses the order of all elements in the + * list, so the last member is now first, and so on. + * + * Example: + * @code + * extern Evas_List *list; + * + * list = evas_list_reverse(list); + * @endcode + * @ingroup Evas_List_Ordering_Group + */ +EAPI Evas_List * +evas_list_reverse(Evas_List *list) +{ + Evas_List *l1, *l2; + + if (!list) return NULL; + l1 = list; + l2 = list->accounting->last; + while (l1 != l2) + { + void *data; + + data = l1->data; + l1->data = l2->data; + l2->data = data; + l1 = l1->next; + if (l1 == l2) break; + l2 = l2->prev; + } + + return list; +} + +/** + * Sort a list according to the ordering func will return + * @param list The list handle to sort + * @param size The length of the list to sort + * @param func A function pointer that can handle comparing the list data + * nodes + * @return A new sorted list + * + * This function sorts your list. The data in your nodes can be arbitrary, + * you just have to be smart enough to know what kind of data is in your + * lists + * + * Example: + * @code + * 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)); + * } + * extern Evas_List *list; + * + * list = evas_list_sort(list, evas_list_count(list), sort_cb); + * if (evas_list_alloc_error()) + * { + * fprintf(stderr, "ERROR: Memory is low. List Sorting failed.\n"); + * exit(-1); + * } + * @endcode + * @ingroup Evas_List_Ordering_Group + */ +EAPI Evas_List * +evas_list_sort(Evas_List *list, int size, int (*func)(void *, void *)) +{ + Evas_List* last; + unsigned int list_number; + unsigned int middle; + int list_size; + + if (!list || !func) + return NULL; + + /* if the caller specified an invalid size, sort the whole list */ + if ((size <= 0) || + (size > list->accounting->count)) + size = list->accounting->count; + + last = list->accounting->last; + middle = size - size / 2; + + for (list_number = middle, list_size = 1; + list_size < middle * 2; + list_number >>= 1, list_size <<= 1) + { + Evas_List *head1 = list; + unsigned int limit = size; + unsigned int process_list; + unsigned int pass_number; + unsigned int split_size = list_size; + + for (process_list = 0; process_list < list_number + 1; ++process_list) + { + Evas_List *head2; + unsigned int size_sum; + int size1, size2; + int i; + + size1 = limit < split_size ? limit : split_size; + limit -= size1; + + size2 = limit < split_size ? limit : split_size; + limit -= size2; + + size_sum = size1 + size2; + + for (head2 = head1, i = 0; i < size1; ++i) + head2 = evas_list_next (head2); + + for (pass_number = 0; pass_number < size_sum; ++pass_number) + { + Evas_List *next; + Evas_List *prev1; + Evas_List *prev2; + + if (size1 == 0 || head1 == NULL) /* List1 is empty, head1 is already at the end of the list. So only need to update head2 */ + { + for (; pass_number < size_sum; ++pass_number) + head2 = evas_list_next (head2); + break; + } + else + if (size2 == 0 || head2 == NULL) /* List2 is empty, just leave */ + break; + else + if (func (head1->data, head2->data) < 0) + { + head1 = evas_list_next (head1); + --size1; + } + else + { + next = evas_list_next (head2); + prev1 = evas_list_prev (head1); + prev2 = evas_list_prev (head2); + + if (next) + next->prev = prev2; + if (prev1) + prev1->next = head2; + if (prev2) + prev2->next = next; + + head2->prev = prev1; + head2->next = head1; + head1->prev = head2; + + --size2; + + if (head1 == list) + list = head2; + if (head2 == last) + last = prev2; + + head2 = next; + } + } + head1 = head2; + } + } + + 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 evas_list_append(), evas_list_prepend(), + * evas_list_append_relative(), or evas_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 + * Evas_List *list = NULL; + * extern void *my_data; + * + * list = evas_list_append(list, my_data); + * if (evas_list_alloc_error()) + * { + * fprintf(stderr, "ERROR: Memory is low. List allocation failed.\n"); + * exit(-1); + * } + * @endcode + * @ingroup Evas_List_General_Group + */ +EAPI int +evas_list_alloc_error(void) +{ + return _evas_list_alloc_error; +} diff --git a/legacy/eina/src/tests/evas_mempool.c b/legacy/eina/src/tests/evas_mempool.c new file mode 100644 index 0000000000..6bbf390968 --- /dev/null +++ b/legacy/eina/src/tests/evas_mempool.c @@ -0,0 +1,188 @@ +/* + * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include + +#include "Evas_Data.h" +#include "evas_mempool.h" + +//#define NOPOOL + +typedef struct _Pool Pool; + +struct _Pool +{ + int usage; + void *base; + Pool *prev, *next; +}; + + +Pool * +_evas_mp_pool_new(Evas_Mempool *pool) +#ifdef NOPOOL +{ + static Pool thepool; + return &thepool; +} +#else +{ + Pool *p; + void **ptr; + int item_alloc, i; + + item_alloc = ((pool->item_size + sizeof(void *) - 1) / sizeof(void *)) * sizeof(void *); + p = malloc(sizeof(Pool) + (pool->pool_size * item_alloc)); + ptr = (void **)(((unsigned char *)p) + sizeof(Pool)); + p->usage = 0; + p->base = ptr; + for (i = 0; i < pool->pool_size - 1; i++) + { + *ptr = (void **)(((unsigned char *)ptr) + item_alloc); + ptr = *ptr; + } + *ptr = NULL; + return p; +} +#endif + +void +_evas_mp_pool_free(Pool *p) +#ifdef NOPOOL +{ +} +#else +{ + free(p); +} +#endif + +void * +evas_mempool_malloc(Evas_Mempool *pool, int size) +#ifdef NOPOOL +{ + return malloc(size); +} +#else +{ + Pool *p; + void *mem; + + for (p = pool->first; p; p = p->next) // look 4 pool from 2nd bucket on + { + if (p->base) // base is not NULL - has a free slot + { + if (p->prev) + { + if (pool->last == p) pool->last = p->prev; + p->prev->next = p->next; + p->prev = NULL; + p->next = pool->first; + p->next->prev = p; + pool->first = p; + } + break; + } + } + if (!p) // we have reached the end of the list - no free pools + { + p = _evas_mp_pool_new(pool); + if (!p) return NULL; + p->prev = NULL; + p->next = pool->first; + if (p->next) p->next->prev = p; + if (!pool->last) pool->last = p; + pool->first = p; + } + mem = p->base; // this points to the next free block - so take it + p->base = *((void **)mem); // base now points to the next free block + if (!p->base) // move to end - it just filled up + { + if (p->next) + { + if (p->prev) p->prev->next = p->next; + else pool->first = p->next; + p->next->prev = p->prev; + ((Pool *)pool->last)->next = p; + p->prev = pool->last; + p->next = NULL; + pool->last = p; + } + } + p->usage++; + pool->usage++; + return mem; +} +#endif + +void +evas_mempool_free(Evas_Mempool *pool, void *ptr) +#ifdef NOPOOL +{ + free(ptr); +} +#else +{ + Pool *p; + void *pmem; + int item_alloc, psize; + + item_alloc = ((pool->item_size + sizeof(void *) - 1) / sizeof(void *)) * sizeof(void *); + psize = item_alloc * pool->pool_size; + for (p = (Pool *)(pool->first); p; p = p->next) // look 4 pool + { + pmem = (void *)(((unsigned char *)p) + sizeof(Pool)); // pool mem base + if ((ptr >= pmem) && ((unsigned char *)ptr < (((unsigned char *)pmem) + psize))) // is it in pool mem? + { + *((void **)ptr) = p->base; // freed node points to prev free node + p->base = ptr; // next free node is now the one we freed + p->usage--; + pool->usage--; + if (p->usage == 0) // free bucket + { + if (p->prev) p->prev->next = p->next; + if (p->next) p->next->prev = p->prev; + if (pool->last == p) pool->last = p->prev; + if (pool->first == p) pool->first = p->next; + _evas_mp_pool_free(p); + } + else + { + if (p->prev) // if not the first - move to front + { + p->prev->next = p->next; + if (p->next) p->next->prev = p->prev; + if (pool->last == p) pool->last = p->prev; + p->prev = NULL; + p->next = pool->first; + p->next->prev = p; + pool->first = p; + } + } + break; + } + } +} +#endif + +void * +evas_mempool_calloc(Evas_Mempool *pool, int size) +#ifdef NOPOOL +{ + return calloc(1, size); +} +#else +{ + void *mem; + + mem = evas_mempool_malloc(pool, size); + memset(mem, 0, size); + return mem; +} +#endif diff --git a/legacy/eina/src/tests/evas_mempool.h b/legacy/eina/src/tests/evas_mempool.h new file mode 100644 index 0000000000..b1d52837f5 --- /dev/null +++ b/legacy/eina/src/tests/evas_mempool.h @@ -0,0 +1,25 @@ +/* + * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 + */ + +#ifndef _EVAS_MEMPOOL_H +#define _EVAS_MEMPOOL_H + + +typedef struct _Evas_Mempool Evas_Mempool; + +struct _Evas_Mempool +{ + int item_size; + int pool_size; + int usage; + void *first, *last; +}; + + +void *evas_mempool_malloc(Evas_Mempool *pool, int size); +void evas_mempool_free(Evas_Mempool *pool, void *ptr); +void *evas_mempool_calloc(Evas_Mempool *pool, int size); + + +#endif /* _EVAS_MEMPOOL_H */ diff --git a/legacy/eina/src/tests/evas_object_list.c b/legacy/eina/src/tests/evas_object_list.c new file mode 100644 index 0000000000..d77687c4a1 --- /dev/null +++ b/legacy/eina/src/tests/evas_object_list.c @@ -0,0 +1,164 @@ +/* + * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include + +#include "Evas_Data.h" + +/* list ops */ +void * +evas_object_list_append(void *in_list, void *in_item) +{ + Evas_Object_List *l, *new_l; + Evas_Object_List *list; + + list = in_list; + new_l = in_item; + new_l->next = NULL; + if (!list) + { + new_l->prev = NULL; + new_l->last = new_l; + return new_l; + } + if (list->last) l = list->last; + else for (l = list; (l) && (l->next); l = l->next); + l->next = new_l; + new_l->prev = l; + list->last = new_l; + return list; +} + +void * +evas_object_list_prepend(void *in_list, void *in_item) +{ + Evas_Object_List *new_l; + Evas_Object_List *list; + + list = in_list; + new_l = in_item; + new_l->prev = NULL; + if (!list) + { + new_l->next = NULL; + new_l->last = new_l; + return new_l; + } + new_l->next = list; + list->prev = new_l; + new_l->last = list->last; + list->last = NULL; + return new_l; +} + +void * +evas_object_list_append_relative(void *in_list, void *in_item, void *in_relative) +{ + Evas_Object_List *list, *relative, *new_l; + + list = in_list; + new_l = in_item; + relative = in_relative; + if (relative) + { + if (relative->next) + { + new_l->next = relative->next; + relative->next->prev = new_l; + } + else new_l->next = NULL; + relative->next = new_l; + new_l->prev = relative; + if (!new_l->next) list->last = new_l; + return list; + } + return evas_object_list_append(list, new_l); +} + +void * +evas_object_list_prepend_relative(void *in_list, void *in_item, void *in_relative) +{ + Evas_Object_List *list, *relative, *new_l; + + list = in_list; + new_l = in_item; + relative = in_relative; + if (relative) + { + new_l->prev = relative->prev; + new_l->next = relative; + relative->prev = new_l; + if (new_l->prev) + { + new_l->prev->next = new_l; + if (!new_l->next) + list->last = new_l; + return list; + } + else + { + if (!new_l->next) + new_l->last = new_l; + else + { + new_l->last = list->last; + list->last = NULL; + } + return new_l; + } + } + return evas_object_list_prepend(list, new_l); +} + +void * +evas_object_list_remove(void *in_list, void *in_item) +{ + Evas_Object_List *return_l; + Evas_Object_List *list, *item; + + /* checkme */ + if(!in_list) + return in_list; + + list = in_list; + item = in_item; + if (!item) return list; + if (item->next) + item->next->prev = item->prev; + if (item->prev) + { + item->prev->next = item->next; + return_l = list; + } + else + { + return_l = item->next; + if (return_l) + return_l->last = list->last; + } + if (item == list->last) + list->last = item->prev; + item->next = NULL; + item->prev = NULL; + return return_l; +} + +void * +evas_object_list_find(void *in_list, void *in_item) +{ + Evas_Object_List *l; + Evas_Object_List *list, *item; + + list = in_list; + item = in_item; + for (l = list; l; l = l->next) + { + if (l == item) return item; + } + return NULL; +} diff --git a/legacy/eina/src/tests/evas_stringshare.c b/legacy/eina/src/tests/evas_stringshare.c new file mode 100644 index 0000000000..b05dcdfda6 --- /dev/null +++ b/legacy/eina/src/tests/evas_stringshare.c @@ -0,0 +1,205 @@ +/* + * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include + + +#include "Evas_Data.h" + +typedef struct _Evas_Stringshare Evas_Stringshare; +typedef struct _Evas_Stringshare_El Evas_Stringshare_El; + +struct _Evas_Stringshare +{ + Evas_Stringshare_El *buckets[1024]; +}; + +struct _Evas_Stringshare_El +{ + Evas_Stringshare_El *next; +// int op; + int references; +}; + +static Evas_Stringshare share = +{ + { + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL + } +}; + +//static int op = 0; +//static FILE *f = NULL; + +static inline int +_evas_stringshare_hash_gen(const char *str, int *len) +{ + unsigned int hash_num = 5381; + const unsigned char *ptr; + + for (ptr = (const unsigned char *)str; *ptr; ptr++) + { + hash_num = (hash_num * 33) ^ *ptr; + } + + hash_num &= 0x3ff; + *len = ptr - (const unsigned char *)str; + return (int)hash_num; +} + +EAPI const char * +evas_stringshare_add(const char *str) +{ + int hash_num, slen; + char *el_str; + Evas_Stringshare_El *el, *pel = NULL; + + if (!str) return NULL; +// if (!f) +// { +// char bf[256]; +// snprintf(bf, sizeof(bf), "strlog-%i", getpid()); +// f = fopen(bf, "w"); +// } + hash_num = _evas_stringshare_hash_gen(str, &slen); + for (el = share.buckets[hash_num]; el; pel = el, el = el->next) + { + el_str = ((char *)el) + sizeof(Evas_Stringshare_El); + if (!strcmp(el_str, str)) + { + if (pel) + { + pel->next = el->next; + el->next = share.buckets[hash_num]; + share.buckets[hash_num] = el; + } + el->references++; +// fprintf(f, "strings[%i] = str->add(strings[%i]);\n", el->op, el->op); +// fflush(f); + return el_str; + } + } + if (!(el = malloc(sizeof(Evas_Stringshare_El) + slen + 1))) return NULL; + el_str = ((char *)el) + sizeof(Evas_Stringshare_El); + strcpy(el_str, str); + el->references = 1; + el->next = share.buckets[hash_num]; + share.buckets[hash_num] = el; +// el->op = op; +// fprintf(f, "strings[%i] = str->add(\"%s\");\n", el->op, el_str); +// fflush(f); +// op++; + return el_str; +} + +EAPI void +evas_stringshare_del(const char *str) +{ + int hash_num, slen; + char *el_str; + Evas_Stringshare_El *el, *pel = NULL; + + if (!str) return; + hash_num = _evas_stringshare_hash_gen(str, &slen); + for (el = share.buckets[hash_num]; el; pel = el, el = el->next) + { + el_str = ((char *)el) + sizeof(Evas_Stringshare_El); + if (el_str == str) + { + el->references--; +// fprintf(f, "str->del(strings[%i]);\n", el->op); +// fflush(f); + if (el->references == 0) + { + if (pel) pel->next = el->next; + else share.buckets[hash_num] = el->next; + free(el); + } + else + { + if (pel) + { + pel->next = el->next; + el->next = share.buckets[hash_num]; + share.buckets[hash_num] = el; + } + } + return; + } + } + printf("EEEK trying to del non-shared stringshare \"%s\"\n", str); + abort(); +}