make the ecore tests stand alone (no ecore installation needed)
authorcaro <caro@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Sun, 24 Jan 2010 10:54:07 +0000 (10:54 +0000)
committercaro <caro@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Sun, 24 Jan 2010 10:54:07 +0000 (10:54 +0000)
so no cyclic dependency

git-svn-id: svn+ssh://svn.enlightenment.org/var/svn/e/trunk/eina@45512 7cbeb6ba-43b4-40fd-8cce-4c39aea84d33

configure.ac
src/tests/Ecore_Data.h [new file with mode: 0644]
src/tests/Makefile.am
src/tests/ecore_hash.c [new file with mode: 0644]
src/tests/ecore_list.c [new file with mode: 0644]
src/tests/ecore_sheap.c [new file with mode: 0644]
src/tests/ecore_strings.c [new file with mode: 0644]
src/tests/eina_bench_array.c
src/tests/eina_bench_hash.c
src/tests/eina_bench_sort.c
src/tests/eina_bench_stringshare.c

index fcbc3cf..06721ac 100644 (file)
@@ -419,7 +419,6 @@ 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([ecore], [${enable_benchmark}], [ecore], [enable_benchmark_ecore="yes"], [enable_benchmark_ecore="no"])
 EINA_BENCH_MODULE([glib], [${enable_benchmark}], [glib-2.0], [enable_benchmark_glib="yes"], [enable_benchmark_glib="no"])
 
 AC_SUBST(requirement_eina)
@@ -490,7 +489,6 @@ echo "  Benchmark............: ${enable_benchmark}"
 if test "x${enable_benchmark}" = "xyes" ; then
 echo "    Glib...............: ${enable_benchmark_glib}"
 echo "    Evas...............: ${enable_benchmark_evas}"
-echo "    Ecore..............: ${enable_benchmark_ecore}"
 echo "    E17 real data......: ${enable_benchmark_e17}"
 fi
 echo
diff --git a/src/tests/Ecore_Data.h b/src/tests/Ecore_Data.h
new file mode 100644 (file)
index 0000000..532403b
--- /dev/null
@@ -0,0 +1,506 @@
+#ifndef _ECORE_DATA_H
+# define _ECORE_DATA_H
+
+#include <stdio.h>
+/* we need this for size_t */
+#include <stddef.h>
+
+#ifdef EAPI
+# undef EAPI
+#endif
+
+#ifdef _WIN32
+# ifdef EFL_ECORE_BUILD
+#  ifdef DLL_EXPORT
+#   define EAPI __declspec(dllexport)
+#  else
+#   define EAPI
+#  endif /* ! DLL_EXPORT */
+# else
+#  define EAPI __declspec(dllimport)
+# endif /* ! EFL_ECORE_BUILD */
+#else
+# ifdef __GNUC__
+#  if __GNUC__ >= 4
+#   define EAPI __attribute__ ((visibility("default")))
+#  else
+#   define EAPI
+#  endif
+# else
+#  define EAPI
+# endif
+#endif /* ! _WIN32 */
+
+/**
+ * @file Ecore_Data.h
+ * @brief Contains threading, list, hash, debugging and tree functions.
+ */
+
+# ifdef __cplusplus
+extern "C" {
+# endif
+
+
+#ifndef TRUE
+# define TRUE 1
+#endif
+
+#ifndef FALSE
+# define FALSE 0
+#endif
+
+#ifdef FREE
+# undef FREE
+#endif
+#define FREE(ptr) free(ptr); ptr = NULL;
+
+#ifdef IF_FREE
+# undef IF_FREE
+#endif
+#define IF_FREE(ptr) if (ptr) free(ptr); ptr = NULL;
+
+/* convenience macros for checking pointer parameters for non-NULL */
+#undef CHECK_PARAM_POINTER_RETURN
+#define CHECK_PARAM_POINTER_RETURN(sparam, param, ret) \
+     if (!(param)) \
+        { \
+           printf("***** Developer Warning ***** :\n" \
+               "\tThis program is calling:\n\n" \
+               "\t%s();\n\n" \
+               "\tWith the parameter:\n\n" \
+               "\t%s\n\n" \
+               "\tbeing NULL. Please fix your program.", __FUNCTION__, sparam); \
+           if (getenv("ECORE_ERROR_ABORT")) abort(); \
+           return ret; \
+        }
+
+#undef CHECK_PARAM_POINTER
+#define CHECK_PARAM_POINTER(sparam, param) \
+     if (!(param)) \
+        { \
+           printf("***** Developer Warning ***** :\n" \
+               "\tThis program is calling:\n\n" \
+               "\t%s();\n\n" \
+               "\tWith the parameter:\n\n" \
+               "\t%s\n\n" \
+               "\tbeing NULL. Please fix your program.", __FUNCTION__, sparam); \
+           if (getenv("ECORE_ERROR_ABORT")) abort(); \
+           return; \
+        }
+
+
+# ifdef __sgi
+#  define __FUNCTION__ "unknown"
+#  ifndef __cplusplus
+#   define inline
+#  endif
+# endif
+   
+# define ECORE_SORT_MIN 0
+# define ECORE_SORT_MAX 1
+
+   typedef void (*Ecore_For_Each) (void *value, void *user_data);
+# define ECORE_FOR_EACH(function) ((Ecore_For_Each)function)
+   
+   typedef void (*Ecore_Free_Cb) (void *data);
+# define ECORE_FREE_CB(func) ((Ecore_Free_Cb)func)
+   
+   typedef unsigned int (*Ecore_Hash_Cb) (const void *key);
+# define ECORE_HASH_CB(function) ((Ecore_Hash_Cb)function)
+   
+   typedef int (*Ecore_Compare_Cb) (const void *data1, const void *data2);
+# define ECORE_COMPARE_CB(function) ((Ecore_Compare_Cb)function)
+   
+   typedef struct _ecore_list Ecore_List;
+# define ECORE_LIST(list) ((Ecore_List *)list)
+   
+   typedef struct _ecore_list_node Ecore_List_Node;
+# define ECORE_LIST_NODE(node) ((Ecore_List_Node *)node)
+
+   typedef struct _ecore_strbuf Ecore_Strbuf;
+# define ECORE_STRBUF(buf) ((Ecore_Strbuf *)buf)
+   
+   struct _ecore_list_node {
+      void *data;
+      struct _ecore_list_node *next;
+   };
+   
+   struct _ecore_list {
+      Ecore_List_Node *first;  /* The first node in the list */
+      Ecore_List_Node *last;   /* The last node in the list */
+      Ecore_List_Node *current;        /* The current node in the list */
+      
+      Ecore_Free_Cb free_func;  /* The callback to free data in nodes */
+      
+      int nodes;               /* The number of nodes in the list */
+      int index;               /* The position from the front of the
+                                list of current node */
+   };
+   
+   EAPI int ecore_direct_compare(const void *key1, const void *key2);
+   EAPI int ecore_str_compare(const void *key1, const void *key2);
+   
+   EAPI unsigned int ecore_direct_hash(const void *key);
+   EAPI unsigned int ecore_str_hash(const void *key);
+   
+   /* Creating and initializing new list structures */
+   EAPI Ecore_List *ecore_list_new(void);
+   EAPI int ecore_list_init(Ecore_List *list);
+   
+   /* Adding items to the list */
+   EAPI int ecore_list_append(Ecore_List * list, void *_data);
+   EAPI int ecore_list_prepend(Ecore_List * list, void *_data);
+   EAPI int ecore_list_insert(Ecore_List * list, void *_data);
+   EAPI int ecore_list_append_list(Ecore_List * list, Ecore_List * append);
+   EAPI int ecore_list_prepend_list(Ecore_List * list, Ecore_List * prepend);
+   
+   /* Removing items from the list */
+   EAPI int ecore_list_remove_destroy(Ecore_List *list);
+   EAPI void *ecore_list_remove(Ecore_List * list);
+   EAPI void *ecore_list_first_remove(Ecore_List * list);
+   EAPI void *ecore_list_last_remove(Ecore_List * list);
+   
+   /* Retrieve the current position in the list */
+   EAPI void *ecore_list_current(Ecore_List * list);
+   EAPI void *ecore_list_first(Ecore_List * list);
+   EAPI void *ecore_list_last(Ecore_List * list);
+   EAPI int ecore_list_index(Ecore_List * list);
+   EAPI int ecore_list_count(Ecore_List * list);
+   
+   /* Traversing the list */
+   EAPI int ecore_list_for_each(Ecore_List *list, Ecore_For_Each function,
+                               void *user_data);
+   EAPI void *ecore_list_first_goto(Ecore_List * list);
+   EAPI void *ecore_list_last_goto(Ecore_List * list);
+   EAPI void *ecore_list_index_goto(Ecore_List * list, int index);
+   EAPI void *ecore_list_goto(Ecore_List * list, const void *_data);
+   
+   /* Traversing the list and returning data */
+   EAPI void *ecore_list_next(Ecore_List * list);
+   EAPI void *ecore_list_find(Ecore_List *list, Ecore_Compare_Cb function,
+        const void *user_data);
+
+   /* Sorting the list */
+   EAPI int ecore_list_sort(Ecore_List *list, Ecore_Compare_Cb compare,
+                                  char order);
+   EAPI int ecore_list_mergesort(Ecore_List *list, Ecore_Compare_Cb compare,
+                                  char order);
+   EAPI int ecore_list_heapsort(Ecore_List *list, Ecore_Compare_Cb compare,
+                                  char order);
+   EAPI void ecore_list_merge(Ecore_List *list, Ecore_List *l2, 
+                                  Ecore_Compare_Cb, char order);
+   
+   /* Check to see if there is any data in the list */
+   EAPI int ecore_list_empty_is(Ecore_List * list);
+   
+   /* Remove every node in the list without freeing the list itself */
+   EAPI int ecore_list_clear(Ecore_List * list);
+   /* Free the list and it's contents */
+   EAPI void ecore_list_destroy(Ecore_List *list);
+   
+   /* Creating and initializing list nodes */
+   EAPI Ecore_List_Node *ecore_list_node_new(void);
+   EAPI int ecore_list_node_init(Ecore_List_Node *newNode);
+   
+   /* Destroying nodes */
+   EAPI int ecore_list_node_destroy(Ecore_List_Node * _e_node, Ecore_Free_Cb free_func);
+   
+   EAPI int ecore_list_free_cb_set(Ecore_List * list, Ecore_Free_Cb free_func);
+   
+   typedef Ecore_List Ecore_DList;
+# define ECORE_DLIST(dlist) ((Ecore_DList *)dlist)
+   
+   typedef struct _ecore_dlist_node Ecore_DList_Node;
+# define ECORE_DLIST_NODE(dlist) ((Ecore_DList_Node *)dlist)
+   
+   struct _ecore_dlist_node {
+      Ecore_List_Node single;
+      Ecore_DList_Node *previous;
+   };
+   
+   /* Creating and initializing new list structures */
+   EAPI Ecore_DList *ecore_dlist_new(void);
+   EAPI int ecore_dlist_init(Ecore_DList *list);
+   EAPI void ecore_dlist_destroy(Ecore_DList *list);
+   
+   /* Adding items to the list */
+   EAPI int ecore_dlist_append(Ecore_DList * _e_dlist, void *_data);
+   EAPI int ecore_dlist_prepend(Ecore_DList * _e_dlist, void *_data);
+   EAPI int ecore_dlist_insert(Ecore_DList * _e_dlist, void *_data);
+   EAPI int ecore_dlist_append_list(Ecore_DList * _e_dlist, Ecore_DList * append);
+   EAPI int ecore_dlist_prepend_list(Ecore_DList * _e_dlist, Ecore_DList * prepend);
+   
+   /* Info about list's state */
+# define ecore_dlist_first(list) ecore_list_first(list)
+# define ecore_dlist_last(list) ecore_list_last(list)
+   EAPI void *ecore_dlist_current(Ecore_DList *list);
+   EAPI int ecore_dlist_index(Ecore_DList *list);
+# define ecore_dlist_count(list) ecore_list_count(list)
+   
+   /* Removing items from the list */
+   EAPI void *ecore_dlist_remove(Ecore_DList * _e_dlist);
+   EAPI void *ecore_dlist_first_remove(Ecore_DList * _e_dlist);
+   EAPI int ecore_dlist_remove_destroy(Ecore_DList *list);
+   EAPI void *ecore_dlist_last_remove(Ecore_DList * _e_dlist);
+   
+   /* Traversing the list */
+# define ecore_dlist_for_each(list, function, user_data) \
+   ecore_list_for_each(list, function, user_data)
+   EAPI void *ecore_dlist_first_goto(Ecore_DList * _e_dlist);
+   EAPI void *ecore_dlist_last_goto(Ecore_DList * _e_dlist);
+   EAPI void *ecore_dlist_index_goto(Ecore_DList * _e_dlist, int index);
+   EAPI void *ecore_dlist_goto(Ecore_DList * _e_dlist, void *_data);
+   
+   /* Traversing the list and returning data */
+   EAPI void *ecore_dlist_next(Ecore_DList * list);
+   EAPI void *ecore_dlist_previous(Ecore_DList * list);
+   
+   /* Sorting the list */
+   EAPI int ecore_dlist_sort(Ecore_DList *list, Ecore_Compare_Cb compare,
+                                  char order);
+   EAPI int ecore_dlist_mergesort(Ecore_DList *list, Ecore_Compare_Cb compare,
+                                  char order);
+# define ecore_dlist_heapsort(list, compare, order) \
+   ecore_list_heapsort(list, compare, order)
+   EAPI void ecore_dlist_merge(Ecore_DList *list, Ecore_DList *l2, 
+                                  Ecore_Compare_Cb, char order);
+   
+   /* Check to see if there is any data in the list */
+   EAPI int ecore_dlist_empty_is(Ecore_DList * _e_dlist);
+   
+   /* Remove every node in the list without free'ing it */
+   EAPI int ecore_dlist_clear(Ecore_DList * _e_dlist);
+   
+   /* Creating and initializing list nodes */
+   EAPI int ecore_dlist_node_init(Ecore_DList_Node * node);
+   EAPI Ecore_DList_Node *ecore_dlist_node_new(void);
+   
+   /* Destroying nodes */
+   EAPI int ecore_dlist_node_destroy(Ecore_DList_Node * node, Ecore_Free_Cb free_func);
+   
+   EAPI int ecore_dlist_free_cb_set(Ecore_DList * dlist, Ecore_Free_Cb free_func);
+   
+   
+   
+   /*
+    * Hash Table Implementation:
+    * 
+    * Traditional hash table implementation. I had tried a list of tables
+    * approach to save on the realloc's but it ended up being much slower than
+    * the traditional approach.
+    */
+   
+   typedef struct _ecore_hash_node Ecore_Hash_Node;
+# define ECORE_HASH_NODE(hash) ((Ecore_Hash_Node *)hash)
+   
+   struct _ecore_hash_node {
+      Ecore_Hash_Node *next; /* Pointer to the next node in the bucket list */
+      void *key;            /* The key for the data node */
+      void *value;          /* The value associated with this node */
+   };
+   
+   typedef struct _ecore_hash Ecore_Hash;
+# define ECORE_HASH(hash) ((Ecore_Hash *)hash)
+   
+   struct _ecore_hash {
+      Ecore_Hash_Node **buckets;
+      int size;                /* An index into the table of primes to
+                        determine size */
+      int nodes;               /* The number of nodes currently in the hash */
+
+      int index;    /* The current index into the bucket table */
+      
+      Ecore_Compare_Cb compare;        /* The function used to compare node values */
+      Ecore_Hash_Cb hash_func; /* The callback function to determine hash */
+      
+      Ecore_Free_Cb free_key;  /* The callback function to free key */
+      Ecore_Free_Cb free_value;        /* The callback function to free value */
+   };
+   
+   /* Create and initialize a hash */
+   EAPI Ecore_Hash *ecore_hash_new(Ecore_Hash_Cb hash_func, Ecore_Compare_Cb compare);
+   EAPI int ecore_hash_init(Ecore_Hash *hash, Ecore_Hash_Cb hash_func, Ecore_Compare_Cb compare);
+   
+   /* Functions related to freeing the data in the hash table */
+   EAPI int ecore_hash_free_key_cb_set(Ecore_Hash *hash, Ecore_Free_Cb function);
+   EAPI int ecore_hash_free_value_cb_set(Ecore_Hash *hash, Ecore_Free_Cb function);
+   EAPI void ecore_hash_destroy(Ecore_Hash *hash);
+
+   EAPI int ecore_hash_count(Ecore_Hash *hash);
+   EAPI int ecore_hash_for_each_node(Ecore_Hash *hash, Ecore_For_Each for_each_func,
+                                    void *user_data);
+   EAPI Ecore_List *ecore_hash_keys(Ecore_Hash *hash);
+   
+   /* Retrieve and store data into the hash */
+   EAPI void *ecore_hash_get(Ecore_Hash *hash, const void *key);
+   EAPI int ecore_hash_set(Ecore_Hash *hash, void *key, void *value);
+   EAPI int ecore_hash_hash_set(Ecore_Hash *hash, Ecore_Hash *set);
+   EAPI void *ecore_hash_remove(Ecore_Hash *hash, const void *key);
+   EAPI void *ecore_hash_find(Ecore_Hash *hash, Ecore_Compare_Cb compare, const void *value);
+   EAPI void ecore_hash_dump_graph(Ecore_Hash *hash);
+   EAPI void ecore_hash_dump_stats(Ecore_Hash *hash);
+
+
+   typedef struct _ecore_heap Ecore_Sheap;
+# define ECORE_HEAP(heap) ((Ecore_Sheap *)heap)
+   
+   struct _ecore_heap {
+      void **data;
+      int size;
+      int space;
+      
+      char order, sorted;
+      
+      /* Callback for comparing node values, default is direct comparison */
+      Ecore_Compare_Cb compare;
+
+      /* Callback for freeing node data, default is NULL */
+      Ecore_Free_Cb free_func;
+   };
+   
+   EAPI Ecore_Sheap *ecore_sheap_new(Ecore_Compare_Cb compare, int size);
+   EAPI void ecore_sheap_destroy(Ecore_Sheap *heap);
+   EAPI int ecore_sheap_init(Ecore_Sheap *heap, Ecore_Compare_Cb compare, int size);
+   EAPI int ecore_sheap_free_cb_set(Ecore_Sheap *heap, Ecore_Free_Cb free_func);
+   EAPI int ecore_sheap_insert(Ecore_Sheap *heap, void *data);
+   EAPI void *ecore_sheap_extract(Ecore_Sheap *heap);
+   EAPI void *ecore_sheap_extreme(Ecore_Sheap *heap);
+   EAPI int ecore_sheap_change(Ecore_Sheap *heap, void *item, void *newval);
+   EAPI int ecore_sheap_compare_set(Ecore_Sheap *heap, Ecore_Compare_Cb compare);
+   EAPI void ecore_sheap_order_set(Ecore_Sheap *heap, char order);
+   EAPI void ecore_sheap_sort(Ecore_Sheap *heap);
+   
+   EAPI void *ecore_sheap_item(Ecore_Sheap *heap, int i);
+   
+  
+   typedef struct _ecore_string Ecore_String; 
+   struct _ecore_string { 
+      char *string; 
+      int references; 
+   }; 
+
+   EAPI int ecore_string_init();
+   EAPI void ecore_string_shutdown();
+   EAPI const char *ecore_string_instance(const char *string);
+   EAPI void ecore_string_release(const char *string);
+   
+   typedef struct _Ecore_Tree_Node Ecore_Tree_Node;
+# define ECORE_TREE_NODE(object) ((Ecore_Tree_Node *)object)
+   struct _Ecore_Tree_Node {
+      
+      /* The actual data for each node */
+      void *key;
+      void *value;
+      
+      /* Pointers to surrounding nodes */
+      Ecore_Tree_Node *parent;
+      Ecore_Tree_Node *left_child;
+      Ecore_Tree_Node *right_child;
+      
+      /* Book keeping information for quicker balancing of the tree */
+      int max_right;
+      int max_left;
+   };
+   
+   typedef struct _Ecore_Tree Ecore_Tree;
+# define ECORE_TREE(object) ((Ecore_Tree *)object)
+   struct _Ecore_Tree {
+      /* Nodes of the tree */
+      Ecore_Tree_Node *tree;
+      
+      /* Callback for comparing node values, default is direct comparison */
+      Ecore_Compare_Cb compare_func;
+      
+      /* Callback for freeing node data, default is NULL */
+      Ecore_Free_Cb free_value;
+      /* Callback for freeing node key, default is NULL */
+      Ecore_Free_Cb free_key;
+   };
+   
+   /* Some basic tree functions */
+   /* Allocate and initialize a new tree */
+   EAPI Ecore_Tree *ecore_tree_new(Ecore_Compare_Cb compare_func);
+   /* Initialize a new tree */
+   EAPI int ecore_tree_init(Ecore_Tree * tree, Ecore_Compare_Cb compare_func);
+   
+   /* Free the tree */
+   EAPI int ecore_tree_destroy(Ecore_Tree * tree);
+   /* Check to see if the tree has any nodes in it */
+   EAPI int ecore_tree_empty_is(Ecore_Tree * tree);
+   
+   /* Retrieve the value associated with key */
+   EAPI void *ecore_tree_get(Ecore_Tree * tree, const void *key);
+   EAPI Ecore_Tree_Node *ecore_tree_get_node(Ecore_Tree * tree, const void *key);
+   /* Retrieve the value of node with key greater than or equal to key */
+   EAPI void *ecore_tree_closest_larger_get(Ecore_Tree * tree, const void *key);
+   /* Retrieve the value of node with key less than or equal to key */
+   EAPI void *ecore_tree_closest_smaller_get(Ecore_Tree * tree, const void *key);
+   
+   /* Set the value associated with key to value */
+   EAPI int ecore_tree_set(Ecore_Tree * tree, void *key, void *value);
+   /* Remove the key from the tree */
+   EAPI int ecore_tree_remove(Ecore_Tree * tree, const void *key);
+   
+   /* Add a node to the tree */
+   EAPI int ecore_tree_node_add(Ecore_Tree * tree, Ecore_Tree_Node * node);
+   /* Remove a node from the tree */
+   EAPI int ecore_tree_node_remove(Ecore_Tree * tree, Ecore_Tree_Node * node);
+   
+   /* For each node in the tree perform the for_each_func function */
+   /* For this one pass in the node */
+   EAPI int ecore_tree_for_each_node(Ecore_Tree * tree, Ecore_For_Each for_each_func,
+                                    void *user_data);
+   /* And here pass in the node's value */
+   EAPI int ecore_tree_for_each_node_value(Ecore_Tree * tree,
+                                          Ecore_For_Each for_each_func,
+                                          void *user_data);
+   
+   /* Some basic node functions */
+   /* Initialize a node */
+   EAPI int ecore_tree_node_init(Ecore_Tree_Node * new_node);
+   /* Allocate and initialize a new node */
+   EAPI Ecore_Tree_Node *ecore_tree_node_new(void);
+   /* Free the desired node */
+   EAPI int ecore_tree_node_destroy(Ecore_Tree_Node * node, 
+                  Ecore_Free_Cb free_value, Ecore_Free_Cb free_key);
+   
+   /* Set the node's key to key */
+   EAPI int ecore_tree_node_key_set(Ecore_Tree_Node * node, void *key);
+   /* Retrieve the key in node */
+   EAPI void *ecore_tree_node_key_get(Ecore_Tree_Node * node);
+   
+   /* Set the node's value to value */
+   EAPI int ecore_tree_node_value_set(Ecore_Tree_Node * node, void *value);
+   /* Retrieve the value in node */
+   EAPI void *ecore_tree_node_value_get(Ecore_Tree_Node * node);
+   
+   /* Add a function to free the data stored in nodes */
+   EAPI int ecore_tree_free_value_cb_set(Ecore_Tree * tree, Ecore_Free_Cb free_value);
+   /* Add a function to free the keys stored in nodes */
+   EAPI int ecore_tree_free_key_cb_set(Ecore_Tree * tree, Ecore_Free_Cb free_key);
+
+
+   EAPI Ecore_Strbuf * ecore_strbuf_new(void);
+   EAPI void ecore_strbuf_free(Ecore_Strbuf *buf);
+   EAPI void ecore_strbuf_append(Ecore_Strbuf *buf, const char *str);
+   EAPI void ecore_strbuf_append_char(Ecore_Strbuf *buf, char c);
+   EAPI void ecore_strbuf_insert(Ecore_Strbuf *buf, const char *str, 
+                                 size_t pos);
+# define ecore_strbuf_prepend(buf, str) ecore_strbuf_insert(buf, str, 0)
+   EAPI const char * ecore_strbuf_string_get(Ecore_Strbuf *buf);
+   EAPI size_t ecore_strbuf_length_get(Ecore_Strbuf *buf);
+   EAPI int ecore_strbuf_replace(Ecore_Strbuf *buf, const char *str, 
+                                 const char *with, unsigned int n);
+# define ecore_strbuf_replace_first(buf, str, with) \
+       ecore_strbuf_replace(buf, str, with, 1)
+   EAPI int ecore_strbuf_replace_all(Ecore_Strbuf *buf, const char *str,
+                                     const char *with);
+
+   extern int ecore_str_compare(const void *key1, const void *key2);
+   extern int ecore_direct_compare(const void *key1, const void *key2);
+   extern unsigned int ecore_str_hash(const void *key);
+
+#ifdef __cplusplus
+}
+#endif
+#endif                         /* _ECORE_DATA_H */
index cb5d3d8..30d69b1 100644 (file)
@@ -13,8 +13,7 @@ AM_CPPFLAGS =                                         \
 -DPACKAGE_BUILD_DIR=\"`pwd`/$(top_builddir)\"  \
 @CHECK_CFLAGS@                                 \
 @GLIB_CFLAGS@                                  \
-@EVAS_CFLAGS@                                  \
-@ECORE_CFLAGS@
+@EVAS_CFLAGS@
 
 if EINA_HAVE_GLIB
 
@@ -28,12 +27,6 @@ AM_CPPFLAGS += -DEINA_BENCH_HAVE_EVAS
 
 endif
 
-if EINA_HAVE_ECORE
-
-AM_CPPFLAGS += -DEINA_BENCH_HAVE_ECORE
-
-endif
-
 if EINA_ENABLE_BENCHMARK_E17
 
 AM_CPPFLAGS += -DEINA_ENABLE_BENCH_E17
@@ -96,9 +89,13 @@ eina_bench_convert.c \
 eina_bench_mempool.c   \
 eina_bench_stringshare_e17.c \
 eina_bench_array.c     \
-eina_bench_rectangle_pool.c
+eina_bench_rectangle_pool.c \
+ecore_list.c \
+ecore_strings.c \
+ecore_hash.c \
+ecore_sheap.c
 
-eina_bench_LDADD = @ECORE_LIBS@ @EVAS_LIBS@ @GLIB_LIBS@ $(top_builddir)/src/lib/libeina.la
+eina_bench_LDADD = @EVAS_LIBS@ @GLIB_LIBS@ $(top_builddir)/src/lib/libeina.la
 
 endif
 
diff --git a/src/tests/ecore_hash.c b/src/tests/ecore_hash.c
new file mode 100644 (file)
index 0000000..56caa3e
--- /dev/null
@@ -0,0 +1,918 @@
+/*
+ * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "Ecore_Data.h"
+
+#define PRIME_TABLE_MAX 21
+#define PRIME_MIN 17
+#define PRIME_MAX 16777213
+
+#define ECORE_HASH_CHAIN_MAX 3
+
+#define ECORE_COMPUTE_HASH(hash, key) hash->hash_func(key) % \
+                                       ecore_prime_table[hash->size];
+
+#define ECORE_HASH_INCREASE(hash) ((hash && ecore_prime_table[hash->size] < PRIME_MAX) ? \
+               (hash->nodes / ecore_prime_table[hash->size]) > \
+               ECORE_HASH_CHAIN_MAX : FALSE)
+#define ECORE_HASH_REDUCE(hash) ((hash && ecore_prime_table[hash->size] > PRIME_MIN) ? \
+               (double)hash->nodes / (double)ecore_prime_table[hash->size-1] \
+               < ((double)ECORE_HASH_CHAIN_MAX * 0.375) : FALSE)
+
+
+static const unsigned int ecore_prime_table[] =
+{
+   17, 31, 61, 127, 257, 509, 1021,
+     2053, 4093, 8191, 16381, 32771, 65537, 131071, 262147, 524287, 1048573,
+     2097143, 4194301, 8388617, 16777213
+};
+
+
+/* Private hash manipulation functions */
+static int _ecore_hash_node_add(Ecore_Hash *hash, Ecore_Hash_Node *node);
+static Ecore_Hash_Node * _ecore_hash_node_get(Ecore_Hash *hash, const void *key);
+static int _ecore_hash_increase(Ecore_Hash *hash);
+static int _ecore_hash_decrease(Ecore_Hash *hash);
+static inline int _ecore_hash_rehash(Ecore_Hash *hash, Ecore_Hash_Node **old_table, int old_size);
+static int _ecore_hash_bucket_destroy(Ecore_Hash_Node *list, Ecore_Free_Cb keyd,
+                                     Ecore_Free_Cb valued);
+static inline Ecore_Hash_Node * _ecore_hash_bucket_get(Ecore_Hash *hash,
+                                               Ecore_Hash_Node *bucket, const void *key);
+
+static Ecore_Hash_Node *_ecore_hash_node_new(void *key, void *value);
+static int _ecore_hash_node_init(Ecore_Hash_Node *node, void *key, void *value);
+static int _ecore_hash_node_destroy(Ecore_Hash_Node *node, Ecore_Free_Cb keyd,
+                                   Ecore_Free_Cb valued);
+
+/**
+ * @defgroup Ecore_Data_Hash_ADT_Creation_Group Hash Creation Functions
+ *
+ * Functions that create hash tables.
+ */
+
+/**
+ * Creates and initializes a new hash
+ * @param hash_func The function for determining hash position.
+ * @param compare   The function for comparing node keys.
+ * @return @c NULL on error, a new hash on success.
+ * @ingroup Ecore_Data_Hash_ADT_Creation_Group
+ */
+EAPI Ecore_Hash *
+ecore_hash_new(Ecore_Hash_Cb hash_func, Ecore_Compare_Cb compare)
+{
+   Ecore_Hash *new_hash = (Ecore_Hash *)malloc(sizeof(Ecore_Hash));
+   if (!new_hash)
+     return NULL;
+
+   if (!ecore_hash_init(new_hash, hash_func, compare))
+     {
+       FREE(new_hash);
+       return NULL;
+     }
+
+   return new_hash;
+}
+
+/**
+ * Initializes the given hash.
+ * @param   hash       The given hash.
+ * @param   hash_func  The function used for hashing node keys.
+ * @param   compare    The function used for comparing node keys.
+ * @return  @c TRUE on success, @c FALSE on an error.
+ * @ingroup Ecore_Data_Hash_ADT_Creation_Group
+ */
+EAPI int
+ecore_hash_init(Ecore_Hash *hash, Ecore_Hash_Cb hash_func, Ecore_Compare_Cb compare)
+{
+   CHECK_PARAM_POINTER_RETURN("hash", hash, FALSE);
+
+   memset(hash, 0, sizeof(Ecore_Hash));
+
+   hash->hash_func = hash_func;
+   hash->compare = compare;
+
+   hash->buckets = (Ecore_Hash_Node **)calloc(ecore_prime_table[0],
+                                             sizeof(Ecore_Hash_Node *));
+
+   return TRUE;
+}
+
+/**
+ * @defgroup Ecore_Data_Hash_ADT_Destruction_Group Hash Destruction Functions
+ *
+ * Functions that destroy hash tables and their contents.
+ */
+
+/**
+ * Sets the function to destroy the keys of the given hash.
+ * @param   hash     The given hash.
+ * @param   function The function used to free the node keys. NULL is a
+ *          valid value and means that no function will be called.
+ * @return  @c TRUE on success, @c FALSE on error.
+ * @ingroup Ecore_Data_Hash_ADT_Destruction_Group
+ */
+EAPI int
+ecore_hash_free_key_cb_set(Ecore_Hash *hash, Ecore_Free_Cb function)
+{
+   CHECK_PARAM_POINTER_RETURN("hash", hash, FALSE);
+
+   hash->free_key = function;
+
+   return TRUE;
+}
+
+/**
+ * Sets the function to destroy the values in the given hash.
+ * @param   hash     The given hash.
+ * @param   function The function that will free the node values. NULL is a
+ *          valid value and means that no function will be called.
+ * @return  @c TRUE on success, @c FALSE on error
+ * @ingroup Ecore_Data_Hash_ADT_Destruction_Group
+ */
+EAPI int
+ecore_hash_free_value_cb_set(Ecore_Hash *hash, Ecore_Free_Cb function)
+{
+   CHECK_PARAM_POINTER_RETURN("hash", hash, FALSE);
+
+   hash->free_value = function;
+
+   return TRUE;
+}
+
+/**
+ * @defgroup Ecore_Data_Hash_ADT_Data_Group Hash Data Functions
+ *
+ * Functions that set, access and delete values from the hash tables.
+ */
+
+/**
+ * Sets a key-value pair in the given hash table.
+ * @param   hash    The given hash table.
+ * @param   key     The key.
+ * @param   value   The value.
+ * @return  @c TRUE if successful, @c FALSE if not.
+ * @ingroup Ecore_Data_Hash_ADT_Data_Group
+ */
+EAPI int
+ecore_hash_set(Ecore_Hash *hash, void *key, void *value)
+{
+   int ret = FALSE;
+   Ecore_Hash_Node *node;
+
+   CHECK_PARAM_POINTER_RETURN("hash", hash, FALSE);
+
+   node = _ecore_hash_node_get(hash, key);
+   if (node)
+     {
+       if (hash->free_key) hash->free_key(key);
+       if (node->value && hash->free_value) hash->free_value(node->value);
+       node->value = value;
+       ret = TRUE;
+     }
+   else
+     {
+       node = _ecore_hash_node_new(key, value);
+       if (node)
+         ret = _ecore_hash_node_add(hash, node);
+     }
+
+   return ret;
+}
+
+/**
+ * Sets all key-value pairs from set in the given hash table.
+ * @param   hash    The given hash table.
+ * @param   set     The hash table to import.
+ * @return  @c TRUE if successful, @c FALSE if not.
+ * @ingroup Ecore_Data_Hash_ADT_Data_Group
+ */
+EAPI int
+ecore_hash_hash_set(Ecore_Hash *hash, Ecore_Hash *set)
+{
+   unsigned int i;
+   Ecore_Hash_Node *node, *old;
+
+   CHECK_PARAM_POINTER_RETURN("hash", hash, FALSE);
+   CHECK_PARAM_POINTER_RETURN("set", set, FALSE);
+
+   for (i = 0; i < ecore_prime_table[set->size]; i++)
+     {
+       /* Hash into a new list to avoid loops of rehashing the same nodes */
+       while ((old = set->buckets[i]))
+         {
+            set->buckets[i] = old->next;
+            old->next = NULL;
+            node = _ecore_hash_node_get(hash, old->key);
+            if (node)
+              {
+                 /* This key already exists. Delete the old and add the new
+                  * value */
+                 if (hash->free_key) hash->free_key(node->key);
+                 if (hash->free_value) hash->free_key(node->value);
+                 node->key = old->key;
+                 node->value = old->value;
+                 free(old);
+              }
+            else
+              _ecore_hash_node_add(hash, old);
+         }
+     }
+   FREE(set->buckets);
+   ecore_hash_init(set, set->hash_func, set->compare);
+   return TRUE;
+}
+
+/**
+ * Frees the hash table and the data contained inside it.
+ * @param   hash The hash table to destroy.
+ * @return  @c TRUE on success, @c FALSE on error.
+ * @ingroup Ecore_Data_Hash_ADT_Destruction_Group
+ */
+EAPI void
+ecore_hash_destroy(Ecore_Hash *hash)
+{
+   unsigned int i = 0;
+
+   CHECK_PARAM_POINTER("hash", hash);
+
+   if (hash->buckets)
+     {
+       while (i < ecore_prime_table[hash->size])
+         {
+            if (hash->buckets[i])
+              {
+                 Ecore_Hash_Node *bucket;
+
+                               /*
+                                * Remove the bucket list to avoid possible recursion
+                                * on the free callbacks.
+                                */
+                 bucket = hash->buckets[i];
+                 hash->buckets[i] = NULL;
+                 _ecore_hash_bucket_destroy(bucket,
+                                            hash->free_key,
+                                            hash->free_value);
+              }
+            i++;
+         }
+
+       FREE(hash->buckets);
+     }
+   FREE(hash);
+
+   return;
+}
+
+/**
+ * @defgroup Ecore_Data_Hash_ADT_Traverse_Group Hash Traverse Functions
+ *
+ * Functions that iterate through hash tables.
+ */
+
+/**
+ * Counts the number of nodes in a hash table.
+ * @param   hash The hash table to count current nodes.
+ * @return  The number of nodes in the hash.
+ * @ingroup Ecore_Data_Hash_ADT_Destruction_Group
+ */
+EAPI int
+ecore_hash_count(Ecore_Hash *hash)
+{
+   CHECK_PARAM_POINTER_RETURN("hash", hash, 0);
+
+   return hash->nodes;
+}
+
+/**
+ * Runs the @p for_each_func function on each entry in the given hash.
+ * @param   hash          The given hash.
+ * @param   for_each_func The function that each entry is passed to.
+ * @param              user_data                       a pointer passed to calls of for_each_func
+ * @return  TRUE on success, FALSE otherwise.
+ * @ingroup Ecore_Data_Hash_ADT_Traverse_Group
+ */
+EAPI int
+ecore_hash_for_each_node(Ecore_Hash *hash, Ecore_For_Each for_each_func, void *user_data)
+{
+   unsigned int i = 0;
+
+   CHECK_PARAM_POINTER_RETURN("hash", hash, FALSE);
+   CHECK_PARAM_POINTER_RETURN("for_each_func", for_each_func, FALSE);
+
+   while (i < ecore_prime_table[hash->size])
+     {
+       if (hash->buckets[i])
+         {
+            Ecore_Hash_Node *node;
+
+            for (node = hash->buckets[i]; node; node = node->next)
+              {
+                 for_each_func(node, user_data);
+              }
+         }
+       i++;
+     }
+
+   return TRUE;
+}
+
+/**
+ * Retrieves an ecore_list of all keys in the given hash.
+ * @param   hash          The given hash.
+ * @return  new ecore_list on success, NULL otherwise
+ * @ingroup Ecore_Data_Hash_ADT_Traverse_Group
+ */
+EAPI Ecore_List *
+ecore_hash_keys(Ecore_Hash *hash)
+{
+   unsigned int i = 0;
+   Ecore_List *keys;
+
+   CHECK_PARAM_POINTER_RETURN("hash", hash, NULL);
+
+   keys = ecore_list_new();
+   while (i < ecore_prime_table[hash->size])
+     {
+       if (hash->buckets[i])
+         {
+            Ecore_Hash_Node *node;
+
+            for (node = hash->buckets[i]; node; node = node->next)
+              {
+                 ecore_list_append(keys, node->key);
+              }
+         }
+       i++;
+     }
+   ecore_list_first_goto(keys);
+
+   return keys;
+}
+
+/**
+ * Prints the distribution of the given hash table for graphing.
+ * @param hash The given hash table.
+ */
+EAPI void
+ecore_hash_dump_graph(Ecore_Hash *hash)
+{
+   unsigned int i;
+
+   for (i = 0; i < ecore_prime_table[hash->size]; i++)
+     if (hash->buckets[i])
+       {
+         int n = 0;
+         Ecore_Hash_Node *node;
+         for (node = hash->buckets[i]; node; node = node->next)
+           n++;
+         printf("%d\t%u", i, n);
+       }
+   else
+     printf("%d\t0", i);
+}
+
+/**
+ * Prints the distribution of the given hash table for graphing.
+ * @param hash The given hash table.
+ */
+EAPI void
+ecore_hash_dump_stats(Ecore_Hash *hash)
+{
+   unsigned int i;
+   double variance, sum_n_2 = 0, sum_n = 0;
+
+   for (i = 0; i < ecore_prime_table[hash->size]; i++)
+     {
+       if (hash->buckets[i])
+         {
+            int n = 0;
+            Ecore_Hash_Node *node;
+            for (node = hash->buckets[i]; node; node = node->next)
+              n++;
+            sum_n_2 += ((double)n * (double)n);
+            sum_n += (double)n;
+         }
+     }
+   variance = (sum_n_2 - ((sum_n * sum_n) / (double)i)) / (double)i;
+   printf("Average length: %f\n\tvariance^2: %f", (sum_n / (double)i),
+         variance);
+}
+
+static int
+_ecore_hash_bucket_destroy(Ecore_Hash_Node *list, Ecore_Free_Cb keyd, Ecore_Free_Cb valued)
+{
+   Ecore_Hash_Node *node;
+
+   CHECK_PARAM_POINTER_RETURN("list", list, FALSE);
+
+   for (node = list; node; node = list)
+     {
+       list = list->next;
+       _ecore_hash_node_destroy(node, keyd, valued);
+     }
+
+   return TRUE;
+}
+
+/*
+ * @brief Add the node to the hash table
+ * @param hash: the hash table to add the key
+ * @param node: the node to add to the hash table
+ * @return Returns FALSE on error, TRUE on success
+ */
+static int
+_ecore_hash_node_add(Ecore_Hash *hash, Ecore_Hash_Node *node)
+{
+   unsigned long hash_val;
+
+   CHECK_PARAM_POINTER_RETURN("hash", hash, FALSE);
+   CHECK_PARAM_POINTER_RETURN("node", node, FALSE);
+
+   /* Check to see if the hash needs to be resized */
+   if (ECORE_HASH_INCREASE(hash))
+     _ecore_hash_increase(hash);
+
+   /* Compute the position in the table */
+   if (!hash->hash_func)
+     hash_val = (unsigned long)node->key % ecore_prime_table[hash->size];
+   else
+     hash_val = ECORE_COMPUTE_HASH(hash, node->key);
+
+   /* Prepend the node to the list at the index position */
+   node->next = hash->buckets[hash_val];
+   hash->buckets[hash_val] = node;
+   hash->nodes++;
+
+   return TRUE;
+}
+
+/**
+ * Retrieves the value associated with the given key from the given hash
+ * table.
+ * @param   hash The given hash table.
+ * @param   key  The key to search for.
+ * @return  The value corresponding to key on success, @c NULL otherwise.
+ * @ingroup Ecore_Data_Hash_ADT_Data_Group
+ */
+EAPI void *
+ecore_hash_get(Ecore_Hash *hash, const void *key)
+{
+   void *data;
+   Ecore_Hash_Node *node;
+
+   CHECK_PARAM_POINTER_RETURN("hash", hash, NULL);
+
+   node = _ecore_hash_node_get(hash, key);
+   if (!node)
+     return NULL;
+
+   data = node->value;
+
+   return data;
+}
+
+/**
+ * Removes the value associated with the given key in the given hash
+ * table.
+ * @param   hash The given hash table.
+ * @param   key  The key to search for.
+ * @return  The value corresponding to the key on success.  @c NULL is
+ *          returned if there is an error.
+ * @ingroup Ecore_Data_Hash_ADT_Data_Group
+ */
+EAPI void *
+ecore_hash_remove(Ecore_Hash *hash, const void *key)
+{
+   Ecore_Hash_Node *node = NULL;
+   Ecore_Hash_Node *list;
+   unsigned long hash_val;
+   void *ret = NULL;
+
+   CHECK_PARAM_POINTER_RETURN("hash", hash, NULL);
+
+   /* Compute the position in the table */
+   if (!hash->hash_func)
+     hash_val = (unsigned long )key % ecore_prime_table[hash->size];
+   else
+     hash_val = ECORE_COMPUTE_HASH(hash, key);
+
+   /*
+    * If their is a list that could possibly hold the key/value pair
+    * traverse it and remove the hash node.
+    */
+   if (hash->buckets[hash_val])
+     {
+       list = hash->buckets[hash_val];
+
+       /*
+        * Traverse the list to find the specified key
+        */
+       node = list;
+       if (hash->compare)
+         {
+            while ((node) && (hash->compare(node->key, key) != 0))
+              {
+                 list = node;
+                 node = node->next;
+              }
+         }
+       else
+         {
+            while ((node) && (node->key != key))
+              {
+                 list = node;
+                 node = node->next;
+              }
+         }
+
+       /*
+        * Remove the node with the matching key and free it's memory
+        */
+       if (node)
+         {
+            if (list == node)
+              hash->buckets[hash_val] = node->next;
+            else
+              list->next = node->next;
+            ret = node->value;
+            node->value = NULL;
+            _ecore_hash_node_destroy(node, hash->free_key, NULL);
+            hash->nodes--;
+         }
+     }
+
+   if (ECORE_HASH_REDUCE(hash))
+     _ecore_hash_decrease(hash);
+
+   return ret;
+}
+
+/**
+ * Retrieves the first value that matches
+ * table.
+ * @param   hash The given hash table.
+ * @param   key  The key to search for.
+ * @return  The value corresponding to key on success, @c NULL otherwise.
+ * @ingroup Ecore_Data_Hash_ADT_Data_Group
+ */
+EAPI void *
+ecore_hash_find(Ecore_Hash *hash, Ecore_Compare_Cb compare, const void *value)
+{
+   unsigned int i = 0;
+
+   CHECK_PARAM_POINTER_RETURN("hash", hash, NULL);
+   CHECK_PARAM_POINTER_RETURN("compare", compare, NULL);
+   CHECK_PARAM_POINTER_RETURN("value", value, NULL);
+
+   while (i < ecore_prime_table[hash->size])
+     {
+       if (hash->buckets[i])
+         {
+            Ecore_Hash_Node *node;
+
+            for (node = hash->buckets[i]; node; node = node->next)
+              {
+                 if (!compare(node->value, value)) return node->value;
+              }
+         }
+       i++;
+     }
+
+   return NULL;
+}
+
+/*
+ * @brief Retrieve the node associated with key
+ * @param hash: the hash table to search for the key
+ * @param key: the key to search for in the hash table
+ * @return Returns NULL on error, node corresponding to key on success
+ */
+static Ecore_Hash_Node *
+_ecore_hash_node_get(Ecore_Hash *hash, const void *key)
+{
+   unsigned long hash_val;
+   Ecore_Hash_Node *node = NULL;
+
+   CHECK_PARAM_POINTER_RETURN("hash", hash, NULL);
+
+   if (!hash->buckets)
+     {
+       return NULL;
+     }
+
+   /* Compute the position in the table */
+   if (!hash->hash_func)
+     hash_val = (unsigned long)key % ecore_prime_table[hash->size];
+   else
+     hash_val = ECORE_COMPUTE_HASH(hash, key);
+
+   /* Grab the bucket at the specified position */
+   if (hash->buckets[hash_val])
+     {
+       node = _ecore_hash_bucket_get(hash, hash->buckets[hash_val], key);
+       /*
+        * Move matched node to the front of the list as it's likely
+        * to be searched for again soon.
+        */
+       if (node && node != hash->buckets[hash_val])
+         {
+            node->next = hash->buckets[hash_val];
+            hash->buckets[hash_val] = node;
+         }
+     }
+
+   return node;
+}
+
+/*
+ * @brief Search the hash bucket for a specified key
+ * @param hash: the hash table to retrieve the comparison function
+ * @param bucket: the list to search for the key
+ * @param key: the key to search for in the list
+ * @return Returns NULL on error or not found, the found node on success
+ */
+static inline Ecore_Hash_Node *
+_ecore_hash_bucket_get(Ecore_Hash *hash, Ecore_Hash_Node *bucket, const void *key)
+{
+   Ecore_Hash_Node *prev = NULL;
+   Ecore_Hash_Node *node = NULL;
+
+   /*
+    * Traverse the list to find the desired node, if the node is in the
+    * list, then return the node.
+    */
+   if (hash->compare)
+     {
+       for (node = bucket; node; node = node->next)
+         {
+            if (hash->compare(node->key, key) == 0)
+              break;
+            prev = node;
+         }
+     }
+   else
+     {
+       for (node = bucket; node; node = node->next)
+         {
+            if (node->key == key)
+              break;
+            prev = node;
+         }
+     }
+
+   /*
+    * Remove node from the list to replace it at the beginning.
+    */
+   if (node && prev)
+     {
+       prev->next = node->next;
+       node->next = NULL;
+     }
+
+   return node;
+}
+
+/*
+ * @brief Increase the size of the hash table by approx.  2 * current size
+ * @param hash: the hash table to increase the size of
+ * @return Returns TRUE on success, FALSE on error
+ */
+static int
+_ecore_hash_increase(Ecore_Hash *hash)
+{
+   void *old;
+
+   CHECK_PARAM_POINTER_RETURN("hash", hash, FALSE);
+
+   /* Max size reached so return FALSE */
+   if ((ecore_prime_table[hash->size] == PRIME_MAX) || (hash->size == PRIME_TABLE_MAX))
+     return FALSE;
+
+   /*
+    * Increase the size of the hash and save a pointer to the old data
+    */
+   hash->size++;
+   old = hash->buckets;
+
+   /*
+    * Allocate a new bucket area, of the new larger size
+    */
+   hash->buckets = calloc(ecore_prime_table[hash->size], sizeof(Ecore_Hash_Node *));
+
+   /*
+    * Make sure the allocation succeeded, if not replace the old data and
+    * return a failure.
+    */
+   if (!hash->buckets)
+     {
+       hash->buckets = old;
+       hash->size--;
+       return FALSE;
+     }
+   hash->nodes = 0;
+
+   /*
+    * Now move all of the old data into the new bucket area
+    */
+   if (_ecore_hash_rehash(hash, old, hash->size - 1))
+     {
+       FREE(old);
+       return TRUE;
+     }
+
+   /*
+    * Free the old buckets regardless of success.
+    */
+   FREE(old);
+
+   return FALSE;
+}
+
+/*
+ * @brief Decrease the size of the hash table by < 1/2 * current size
+ * @param hash: the hash table to decrease the size of
+ * @return Returns TRUE on success, FALSE on error
+ */
+static int
+_ecore_hash_decrease(Ecore_Hash *hash)
+{
+   Ecore_Hash_Node **old;
+
+   CHECK_PARAM_POINTER_RETURN("hash", hash, FALSE);
+
+   if (ecore_prime_table[hash->size] == PRIME_MIN)
+     return FALSE;
+
+   /*
+    * Decrease the hash size and store a pointer to the old data
+    */
+   hash->size--;
+   old = hash->buckets;
+
+   /*
+    * Allocate a new area to store the data
+    */
+   hash->buckets = (Ecore_Hash_Node **)calloc(ecore_prime_table[hash->size],
+                                             sizeof(Ecore_Hash_Node *));
+
+   /*
+    * Make sure allocation succeeded otherwise rreturn to the previous
+    * state
+    */
+   if (!hash->buckets)
+     {
+       hash->buckets = old;
+       hash->size++;
+       return FALSE;
+     }
+
+   hash->nodes = 0;
+
+   if (_ecore_hash_rehash(hash, old, hash->size + 1))
+     {
+       FREE(old);
+       return TRUE;
+     }
+
+   return FALSE;
+}
+
+/*
+ * @brief Rehash the nodes of a table into the hash table
+ * @param hash: the hash to place the nodes of the table
+ * @param table: the table to remove the nodes from and place in hash
+ * @return Returns TRUE on success, FALSE on error
+ */
+static inline int
+_ecore_hash_rehash(Ecore_Hash *hash, Ecore_Hash_Node **old_table, int old_size)
+{
+   unsigned int i;
+   Ecore_Hash_Node *old;
+
+   CHECK_PARAM_POINTER_RETURN("hash", hash, FALSE);
+   CHECK_PARAM_POINTER_RETURN("old_table", old_table, FALSE);
+
+   for (i = 0; i < ecore_prime_table[old_size]; i++)
+     {
+       /* Hash into a new list to avoid loops of rehashing the same nodes */
+       while ((old = old_table[i]))
+         {
+            old_table[i] = old->next;
+            old->next = NULL;
+            _ecore_hash_node_add(hash, old);
+         }
+     }
+
+   return TRUE;
+}
+
+/*
+ * @brief Create a new hash node for key and value storage
+ * @param key: the key for this node
+ * @param value: the value that the key references
+ * @return Returns NULL on error, a new hash node on success
+ */
+static Ecore_Hash_Node *
+_ecore_hash_node_new(void *key, void *value)
+{
+   Ecore_Hash_Node *node;
+
+   node = (Ecore_Hash_Node *)malloc(sizeof(Ecore_Hash_Node));
+   if (!node)
+     return NULL;
+
+   if (!_ecore_hash_node_init(node, key, value))
+     {
+       FREE(node);
+       return NULL;
+     }
+
+   return node;
+}
+
+/*
+ * @brief Initialize a hash node to some sane default values
+ * @param node: the node to set the values
+ * @param key: the key to reference this node
+ * @param value: the value that key refers to
+ * @return Returns TRUE on success, FALSE on error
+ */
+static int
+_ecore_hash_node_init(Ecore_Hash_Node *node, void *key, void *value)
+{
+   CHECK_PARAM_POINTER_RETURN("node", node, FALSE);
+
+   node->key = key;
+   node->value = value;
+
+   return TRUE;
+}
+
+/*
+ * @brief Destroy a node and call the specified callbacks to free data
+ * @param node: the node to be destroyed
+ * @param keyd: the function to free the key
+ * @param valued: the function  to free the value
+ * @return Returns TRUE on success, FALSE on error
+ */
+static int
+_ecore_hash_node_destroy(Ecore_Hash_Node *node, Ecore_Free_Cb keyd, Ecore_Free_Cb valued)
+{
+   CHECK_PARAM_POINTER_RETURN("node", node, FALSE);
+
+   if (keyd)
+     keyd(node->key);
+
+   if (valued)
+     valued(node->value);
+
+   FREE(node);
+
+   return TRUE;
+}
+
+int
+ecore_str_compare(const void *key1, const void *key2)
+{
+   const char *k1, *k2;
+
+   if (!key1 || !key2)
+     return ecore_direct_compare(key1, key2);
+   else if (key1 == key2)
+     return 0;
+
+   k1 = key1;
+   k2 = key2;
+
+   return strcmp(k1, k2);
+}
+
+unsigned int
+ecore_str_hash(const void *key)
+{
+   int i;
+   unsigned int mask;
+   unsigned int value = 0;
+   const char *k = key;
+
+   if (!k)
+     return 0;
+
+   mask = (sizeof(unsigned int) * 8) - 1;
+
+   for (i = 0; k[i] != '\0'; i++)
+     {
+       value ^= ((unsigned int) k[i] << ((i * 5) & mask));
+     }
+
+   return value;
+}
diff --git a/src/tests/ecore_list.c b/src/tests/ecore_list.c
new file mode 100644 (file)
index 0000000..487143f
--- /dev/null
@@ -0,0 +1,2116 @@
+/*
+ * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "Ecore_Data.h"
+
+/* Some tests showed that beyond that value heap sort is faster than merge sort
+ * (in this implementation). This value has to be changed or at least review
+ * if someone is changing the implementation. */
+#define ECORE_MERGESORT_LIMIT 40000
+
+/* Return information about the list */
+static void *_ecore_list_current(Ecore_List * list);
+
+/* Adding functions */
+static int _ecore_list_insert(Ecore_List * list, Ecore_List_Node *node);
+static int _ecore_list_append_0(Ecore_List * list, Ecore_List_Node *node);
+static int _ecore_list_prepend_0(Ecore_List * list, Ecore_List_Node *node);
+
+/* Remove functions */
+static void *_ecore_list_remove_0(Ecore_List * list);
+static void *_ecore_list_first_remove(Ecore_List * list);
+static void *_ecore_list_last_remove(Ecore_List * list);
+
+/* Basic traversal functions */
+static void *_ecore_list_next(Ecore_List * list);
+static void *_ecore_list_last_goto(Ecore_List * list);
+static void *_ecore_list_first_goto(Ecore_List * list);
+static void *_ecore_list_goto(Ecore_List * list, const void *data);
+static void *_ecore_list_index_goto(Ecore_List *list, int index);
+
+/* Iterative functions */
+static int _ecore_list_for_each(Ecore_List *list, Ecore_For_Each function,
+                                void *user_data);
+static void *_ecore_list_find(Ecore_List *list, Ecore_Compare_Cb function,
+                              const void *user_data);
+
+/* Sorting functions */
+static Ecore_List_Node *_ecore_list_node_mergesort(Ecore_List_Node *first,
+                                  int n, Ecore_Compare_Cb compare, int order);
+static Ecore_List_Node *_ecore_list_node_merge(Ecore_List_Node *first,
+                                               Ecore_List_Node *second,
+                                               Ecore_Compare_Cb compare,
+                                               int order);
+static Ecore_List_Node *_ecore_dlist_node_mergesort(Ecore_List_Node *first,
+                                  int n, Ecore_Compare_Cb compare, int order);
+static Ecore_List_Node *_ecore_dlist_node_merge(Ecore_List_Node *first,
+                                               Ecore_List_Node *second,
+                                               Ecore_Compare_Cb compare,
+                                               int order);
+
+/* Private double linked list functions */
+static void *_ecore_dlist_previous(Ecore_DList * list);
+static void *_ecore_dlist_first_remove(Ecore_DList *list);
+static void *_ecore_dlist_index_goto(Ecore_DList *list, int index);
+
+/**
+@defgroup Ecore_Data_List_Creation_Group List Creation/Destruction Functions
+
+Functions that create, initialize and destroy Ecore_Lists.
+*/
+
+/**
+ * Create and initialize a new list.
+ * @return  A new initialized list on success, @c NULL on failure.
+ * @ingroup Ecore_Data_List_Creation_Group
+ */
+EAPI Ecore_List *
+ecore_list_new(void)
+{
+   Ecore_List *list;
+
+   list = (Ecore_List *)malloc(sizeof(Ecore_List));
+   if (!list)
+     return NULL;
+
+   if (!ecore_list_init(list))
+     {
+       FREE(list);
+       return NULL;
+     }
+
+   return list;
+}
+
+/**
+ * Initialize a list to some sane starting values.
+ * @param   list The list to initialize.
+ * @return  @c TRUE if successful, @c FALSE if an error occurs.
+ * @ingroup Ecore_Data_List_Creation_Group
+ */
+EAPI int
+ecore_list_init(Ecore_List *list)
+{
+   CHECK_PARAM_POINTER_RETURN("list", list, FALSE);
+
+   memset(list, 0, sizeof(Ecore_List));
+
+   return TRUE;
+}
+
+/**
+ * Free a list and all of it's nodes.
+ * @param   list The list to be freed.
+ * @ingroup Ecore_Data_List_Creation_Group
+ */
+EAPI void
+ecore_list_destroy(Ecore_List *list)
+{
+   void *data;
+
+   CHECK_PARAM_POINTER("list", list);
+
+   while (list->first)
+     {
+       data = _ecore_list_first_remove(list);
+       if (list->free_func)
+         list->free_func(data);
+     }
+
+   FREE(list);
+}
+
+/**
+ * Set the function for freeing data.
+ * @param  list      The list that will use this function when nodes are
+ *                   destroyed.
+ * @param  free_func The function that will free the key data.
+ * @return @c TRUE on successful set, @c FALSE otherwise.
+ */
+EAPI int
+ecore_list_free_cb_set(Ecore_List *list, Ecore_Free_Cb free_func)
+{
+   CHECK_PARAM_POINTER_RETURN("list", list, FALSE);
+
+   list->free_func = free_func;
+
+   return TRUE;
+}
+
+/**
+ * Checks the list for any nodes.
+ * @param  list  The list to check for nodes
+ * @return @c TRUE if no nodes in list, @c FALSE if the list contains nodes
+ */
+EAPI int
+ecore_list_empty_is(Ecore_List *list)
+{
+   int ret = TRUE;
+
+   CHECK_PARAM_POINTER_RETURN("list", list, TRUE);
+
+   if (list->nodes)
+     ret = FALSE;
+
+   return ret;
+}
+
+/**
+ * Returns the number of the current node.
+ * @param  list The list to return the number of the current node.
+ * @return The number of the current node in the list.
+ */
+EAPI int
+ecore_list_index(Ecore_List *list)
+{
+   int ret;
+
+   CHECK_PARAM_POINTER_RETURN("list", list, FALSE);
+
+   ret = list->index;
+
+   return ret;
+}
+
+/**
+ * Find the number of nodes in the list.
+ * @param  list The list to find the number of nodes
+ * @return The number of nodes in the list.
+ */
+EAPI int
+ecore_list_count(Ecore_List *list)
+{
+   int ret = 0;
+
+   CHECK_PARAM_POINTER_RETURN("list", list, FALSE);
+
+   ret = list->nodes;
+
+   return ret;
+}
+
+/**
+@defgroup Ecore_Data_List_Add_Item_Group List Item Adding Functions
+
+Functions that are used to add nodes to an Ecore_List.
+*/
+
+/**
+ * Append data to the list.
+ * @param   list The list.
+ * @param   data The data to append.
+ * @return  @c FALSE if an error occurs, @c TRUE if appended successfully
+ * @ingroup Ecore_Data_List_Add_Item_Group
+ */
+EAPI inline int
+ecore_list_append(Ecore_List *list, void *data)
+{
+   int ret;
+   Ecore_List_Node *node;
+
+   CHECK_PARAM_POINTER_RETURN("list", list, FALSE);
+
+   node = ecore_list_node_new();
+   node->data = data;
+
+   ret = _ecore_list_append_0(list, node);
+
+   return ret;
+}
+
+/* For adding items to the end of the list */
+static int
+_ecore_list_append_0(Ecore_List *list, Ecore_List_Node *end)
+{
+   if (list->last)
+     list->last->next = end;
+
+   list->last = end;
+
+   if (list->first == NULL)
+     {
+       list->first = end;
+       list->index = 0;
+       list->current = NULL;
+     }
+
+   if (list->index >= list->nodes)
+     list->index++;
+
+   list->nodes++;
+
+   return TRUE;
+}
+
+/**
+ * Prepend data to the beginning of the list.
+ * @param  list The list.
+ * @param  data The data to prepend.
+ * @return @c FALSE if an error occurs, @c TRUE if prepended successfully.
+ * @ingroup Ecore_Data_List_Add_Item_Group
+ */
+EAPI inline int
+ecore_list_prepend(Ecore_List *list, void *data)
+{
+   int ret;
+   Ecore_List_Node *node;
+
+   CHECK_PARAM_POINTER_RETURN("list", list, FALSE);
+
+   node = ecore_list_node_new();
+   node->data = data;
+
+   ret = _ecore_list_prepend_0(list, node);
+
+   return ret;
+}
+
+/* For adding items to the beginning of the list */
+static int
+_ecore_list_prepend_0(Ecore_List *list, Ecore_List_Node *start)
+{
+   /* Put it at the beginning of the list */
+   start->next = list->first;
+
+   list->first = start;
+
+   /* If no last node, then the first node is the last node */
+   if (list->last == NULL)
+     list->last = list->first;
+
+   list->nodes++;
+   list->index++;
+
+   return TRUE;
+}
+
+/**
+ * Insert data in front of the current point in the list.
+ * @param   list The list to hold the inserted @p data.
+ * @param   data The data to insert into @p list.
+ * @return  @c FALSE if there is an error, @c TRUE on success
+ * @ingroup Ecore_Data_List_Add_Item_Group
+ */
+EAPI inline int
+ecore_list_insert(Ecore_List *list, void *data)
+{
+   int ret;
+   Ecore_List_Node *node;
+
+   CHECK_PARAM_POINTER_RETURN("list", list, FALSE);
+
+   node = ecore_list_node_new();
+   node->data = data;
+
+   ret = _ecore_list_insert(list, node);
+
+   return ret;
+}
+
+/* For adding items in front of the current position in the list */
+static int
+_ecore_list_insert(Ecore_List *list, Ecore_List_Node *new_node)
+{
+   /*
+    * If the current point is at the beginning of the list, then it's the
+    * same as prepending it to the list.
+    */
+   if (list->current == list->first)
+     return _ecore_list_prepend_0(list, new_node);
+
+   if (list->current == NULL)
+     {
+       int ret_value;
+
+       ret_value = _ecore_list_append_0(list, new_node);
+       list->current = list->last;
+
+       return ret_value;
+     }
+
+   /* Setup the fields of the new node */
+   new_node->next = list->current;
+
+   /* And hook the node into the list */
+   _ecore_list_index_goto(list, ecore_list_index(list) - 1);
+
+   list->current->next = new_node;
+
+   /* Now move the current item to the inserted item */
+   list->current = new_node;
+   list->nodes++;
+
+   return TRUE;
+}
+/**
+ * Append a list to the list.
+ * @param   list The list.
+ * @param   append The list to append.
+ * @return  @c FALSE if an error occurs, @c TRUE if appended successfully
+ * @ingroup Ecore_Data_List_Add_Item_Group
+ */
+
+EAPI int
+ecore_list_append_list(Ecore_List *list, Ecore_List *append)
+{
+   CHECK_PARAM_POINTER_RETURN("list", list, FALSE);
+   CHECK_PARAM_POINTER_RETURN("append", append, FALSE);
+
+   if (ecore_list_empty_is(append)) return TRUE;
+
+   if (ecore_list_empty_is(list))
+     {
+       list->first = append->first;
+       list->current = list->first;
+       list->last = append->last;
+       list->nodes = append->nodes;
+     }
+   else
+     {
+       list->last->next = append->first;
+       list->last = append->last;
+       list->nodes += append->nodes;
+     }
+   ecore_list_init(append);
+   return TRUE;
+}
+
+/**
+ * Prepend a list to the beginning of the list.
+ * @param  list The list.
+ * @param  prepend The list to prepend.
+ * @return @c FALSE if an error occurs, @c TRUE if prepended successfully.
+ * @ingroup Ecore_Data_List_Add_Item_Group
+ */
+EAPI int
+ecore_list_prepend_list(Ecore_List *list, Ecore_List *prepend)
+{
+   CHECK_PARAM_POINTER_RETURN("list", list, FALSE);
+   CHECK_PARAM_POINTER_RETURN("prepend", prepend, FALSE);
+
+   if (ecore_list_empty_is(prepend)) return TRUE;
+
+   if (ecore_list_empty_is(list))
+     {
+       list->first = prepend->first;
+       list->current = NULL;
+       list->last = prepend->last;
+       list->nodes = prepend->nodes;
+     }
+   else
+     {
+       prepend->last->next = list->first;
+       list->first = prepend->first;
+       list->nodes += prepend->nodes;
+       list->index += prepend->nodes;
+     }
+   ecore_list_init(prepend);
+   return TRUE;
+}
+
+/**
+@defgroup Ecore_Data_List_Remove_Item_Group List Item Removing Functions
+
+Functions that remove nodes from an Ecore_List.
+*/
+
+/**
+ * Remove the current item from the list.
+ * @param   list The list to remove the current item
+ * @return  A pointer to the removed data on success, @c NULL on failure.
+ * @ingroup Ecore_Data_List_Remove_Item_Group
+ */
+EAPI inline void *
+ecore_list_remove(Ecore_List *list)
+{
+   void *ret;
+
+   CHECK_PARAM_POINTER_RETURN("list", list, NULL);
+
+   ret = _ecore_list_remove_0(list);
+
+   return ret;
+}
+
+/* Remove the current item from the list */
+static void *
+_ecore_list_remove_0(Ecore_List *list)
+{
+   void *ret = NULL;
+   Ecore_List_Node *old;
+
+   if (!list)
+     return NULL;
+
+   if (ecore_list_empty_is(list))
+     return NULL;
+
+   if (!list->current)
+     return NULL;
+
+   if (list->current == list->first)
+     return _ecore_list_first_remove(list);
+
+   if (list->current == list->last)
+     return _ecore_list_last_remove(list);
+
+   old = list->current;
+
+   _ecore_list_index_goto(list, list->index - 1);
+
+   list->current->next = old->next;
+   old->next = NULL;
+   ret = old->data;
+   old->data = NULL;
+
+   _ecore_list_next(list);
+
+   ecore_list_node_destroy(old, NULL);
+   list->nodes--;
+
+   return ret;
+}
+
+/**
+ * Remove and free the data in lists current position.
+ * @param   list The list to remove and free the current item.
+ * @return  @c TRUE on success, @c FALSE on error
+ * @ingroup Ecore_Data_List_Remove_Item_Group
+ */
+EAPI int
+ecore_list_remove_destroy(Ecore_List *list)
+{
+   void *data;
+
+   CHECK_PARAM_POINTER_RETURN("list", list, FALSE);
+
+   data = _ecore_list_remove_0(list);
+   if (list->free_func)
+     list->free_func(data);
+
+   return TRUE;
+}
+
+/**
+ * Remove the first item from the list.
+ * @param   list The list to remove the current item
+ * @return  Returns a pointer to the removed data on success, @c NULL on
+ *          failure.
+ * @ingroup Ecore_Data_List_Remove_Item_Group
+ */
+EAPI inline void *
+ecore_list_first_remove(Ecore_List *list)
+{
+   void *ret;
+
+   CHECK_PARAM_POINTER_RETURN("list", list, NULL);
+
+   ret = _ecore_list_first_remove(list);
+
+   return ret;
+}
+
+/* Remove the first item from the list */
+static void *
+_ecore_list_first_remove(Ecore_List *list)
+{
+   void *ret = NULL;
+   Ecore_List_Node *old;
+
+   if (!list)
+     return NULL;
+
+   if (ecore_list_empty_is(list))
+     return NULL;
+
+   old = list->first;
+
+   list->first = list->first->next;
+
+   if (list->current == old)
+     list->current = list->first;
+   else
+     (list->index ? list->index-- : 0);
+
+   if (list->last == old)
+     list->last = list->first;
+
+   ret = old->data;
+   old->data = NULL;
+
+   ecore_list_node_destroy(old, NULL);
+   list->nodes--;
+
+   return ret;
+}
+
+/**
+ * Remove the last item from the list.
+ * @param   list The list to remove the last node from
+ * @return  A pointer to the removed data on success, @c NULL on failure.
+ * @ingroup Ecore_Data_List_Remove_Item_Group
+ */
+EAPI inline void *
+ecore_list_last_remove(Ecore_List *list)
+{
+   void *ret;
+
+   CHECK_PARAM_POINTER_RETURN("list", list, NULL);
+
+   ret = _ecore_list_last_remove(list);
+
+   return ret;
+}
+
+/* Remove the last item from the list */
+static void *
+_ecore_list_last_remove(Ecore_List *list)
+{
+   void *ret = NULL;
+   Ecore_List_Node *old, *prev;
+
+   if (!list)
+     return NULL;
+
+   if (ecore_list_empty_is(list))
+     return NULL;
+
+   old = list->last;
+   if (list->current == old)
+     list->current = NULL;
+
+   if (list->first == old)
+     list->first = NULL;
+   for (prev = list->first; prev && prev->next != old; prev = prev->next);
+   list->last = prev;
+   if (prev)
+     prev->next = NULL;
+
+   old->next = NULL;
+   ret = old->data;
+   old->data = NULL;
+
+   ecore_list_node_destroy(old, NULL);
+   list->nodes--;
+
+   return ret;
+}
+
+/**
+@defgroup Ecore_Data_List_Traverse_Group List Traversal Functions
+
+Functions that can be used to traverse an Ecore_List.
+*/
+
+/**
+ * Make the current item the item with the given index number.
+ * @param   list  The list.
+ * @param   index The position to move the current item.
+ * @return  A pointer to new current item on success, @c NULL on failure.
+ * @ingroup Ecore_Data_List_Traverse_Group
+ */
+EAPI inline void *
+ecore_list_index_goto(Ecore_List *list, int index)
+{
+   void *ret;
+
+   CHECK_PARAM_POINTER_RETURN("list", list, NULL);
+
+   ret = _ecore_list_index_goto(list, index);
+
+   return ret;
+}
+
+/* This is the non-threadsafe version, use this inside internal functions that
+ * already lock the list */
+static void *
+_ecore_list_index_goto(Ecore_List *list, int index)
+{
+   int i;
+
+   if (!list)
+     return NULL;
+
+   if (ecore_list_empty_is(list))
+     return NULL;
+
+   if (index > ecore_list_count(list) || index < 0)
+     return NULL;
+
+   if (index < list->index)
+     {
+       _ecore_list_first_goto(list);
+       i = 0;
+     }
+   else
+     i = list->index;
+
+   for (; i < index && _ecore_list_next(list); i++);
+
+   if (i >= list->nodes)
+     return NULL;
+
+   list->index = i;
+
+   return list->current->data;
+}
+
+/**
+ * Make the current item the node that contains @p data.
+ * @param   list The list.
+ * @param   data The data to find.
+ * @return  A pointer to @p data on success, @c NULL on failure.
+ * @ingroup Ecore_Data_List_Traverse_Group
+ */
+EAPI inline void *
+ecore_list_goto(Ecore_List *list, const void *data)
+{
+   void *ret;
+
+   CHECK_PARAM_POINTER_RETURN("list", list, NULL);
+
+   ret = _ecore_list_goto(list, data);
+
+   return ret;
+}
+
+/* Set the current position to the node containing data */
+static void *
+_ecore_list_goto(Ecore_List *list, const void *data)
+{
+   int index;
+   Ecore_List_Node *node;
+
+   if (!list)
+     return NULL;
+
+   index = 0;
+
+   node = list->first;
+   while (node && node->data)
+     {
+       Ecore_List_Node *next;
+
+       if (node->data == data)
+         break;
+
+       next = node->next;
+
+       node = next;
+
+       index++;
+     }
+
+   if (!node)
+     return NULL;
+
+   list->current = node;
+   list->index = index;
+
+   return list->current->data;
+}
+
+/**
+ * Make the current item the first item in the list
+ * @param   list The list.
+ * @return  A pointer to the first item on success, @c NULL on failure
+ * @ingroup Ecore_Data_List_Traverse_Group
+ */
+EAPI inline void *
+ecore_list_first_goto(Ecore_List *list)
+{
+   void *ret;
+
+   CHECK_PARAM_POINTER_RETURN("list", list, NULL);
+
+   ret = _ecore_list_first_goto(list);
+
+   return ret;
+}
+
+/* Set the current position to the start of the list */
+static void *
+_ecore_list_first_goto(Ecore_List *list)
+{
+   if (!list || !list->first)
+     return NULL;
+
+   list->current = list->first;
+   list->index = 0;
+
+   return list->current->data;
+}
+
+/**
+ * Make the current item the last item in the list.
+ * @param   list The list.
+ * @return  A pointer to the last item on success, @c NULL on failure.
+ * @ingroup Ecore_Data_List_Traverse_Group
+ */
+EAPI inline void *
+ecore_list_last_goto(Ecore_List *list)
+{
+   void *ret;
+
+   CHECK_PARAM_POINTER_RETURN("list", list, NULL);
+
+   ret = _ecore_list_last_goto(list);
+
+   return ret;
+}
+
+/* Set the current position to the end of the list */
+static void *
+_ecore_list_last_goto(Ecore_List *list)
+{
+   if (!list || !list->last)
+     return NULL;
+
+   list->current = list->last;
+   list->index = (list->nodes - 1);
+
+   return list->current->data;
+}
+
+/**
+ * Retrieve the data pointed to by the current item in @p list.
+ * @param  list The list.
+ * @return Returns the data at current position, can be @c NULL.
+ */
+EAPI inline void *
+ecore_list_current(Ecore_List *list)
+{
+   void *ret;
+
+   ret = _ecore_list_current(list);
+
+   return ret;
+}
+
+/**
+ * Retrieve the data pointed to by the first item in @p list.
+ * @param  list The list.
+ * @return Returns the data at current position, can be @c NULL.
+ */
+EAPI inline void *
+ecore_list_first(Ecore_List *list)
+{
+   void *ret;
+
+   if (!list->first)
+     return NULL;
+   ret = list->first->data;
+
+   return ret;
+}
+
+/**
+ * Retrieve the data pointed to by the last item in @p list.
+ * @param  list The list.
+ * @return Returns the data at current position, can be @c NULL.
+ */
+EAPI inline void *
+ecore_list_last(Ecore_List *list)
+{
+   void *ret;
+
+   if (!list->last)
+     return NULL;
+   ret = list->last->data;
+
+   return ret;
+}
+
+/* Return the data of the current node without incrementing */
+static void *
+_ecore_list_current(Ecore_List *list)
+{
+   void *ret;
+
+   if (!list->current)
+     return NULL;
+
+   ret = list->current->data;
+
+   return ret;
+}
+
+/**
+ * Retrieve the data pointed to by the current item, and make the next item
+ * the current item.
+ * @param   list The list to retrieve data from.
+ * @return  The current item in the list on success, @c NULL on failure.
+ */
+EAPI inline void *
+ecore_list_next(Ecore_List *list)
+{
+   void *data;
+
+   CHECK_PARAM_POINTER_RETURN("list", list, NULL);
+
+   data = _ecore_list_next(list);
+
+   return data;
+}
+
+/* Return the data contained in the current node and go to the next node */
+static void *
+_ecore_list_next(Ecore_List *list)
+{
+   void *data;
+   Ecore_List_Node *ret;
+   Ecore_List_Node *next;
+
+   if (!list->current)
+     return NULL;
+
+   ret = list->current;
+   next = list->current->next;
+
+   list->current = next;
+   list->index++;
+
+   data = ret->data;
+
+   return data;
+}
+
+/**
+ * Remove all nodes from @p list.
+ * @param  list The list.
+ * @return Returns @c TRUE on success, @c FALSE on error.
+ * @note The data for each item on the list is not freed by
+ *       @c ecore_list_clear().
+ */
+EAPI int
+ecore_list_clear(Ecore_List *list)
+{
+   CHECK_PARAM_POINTER_RETURN("list", list, FALSE);
+
+   while (!ecore_list_empty_is(list))
+     _ecore_list_first_remove(list);
+
+   return TRUE;
+}
+
+/**
+ * Execute function for each node in @p list.
+ * @param   list     The list.
+ * @param   function The function to pass each node from @p list to.
+ * @return  Returns @c TRUE on success, @c FALSE on failure.
+ * @ingroup Ecore_Data_List_Traverse_Group
+ */
+EAPI int
+ecore_list_for_each(Ecore_List *list, Ecore_For_Each function, void *user_data)
+{
+   int ret;
+
+   CHECK_PARAM_POINTER_RETURN("list", list, FALSE);
+
+   ret = _ecore_list_for_each(list, function, user_data);
+
+   return ret;
+}
+
+/* The real meat of executing the function for each data node */
+static int
+_ecore_list_for_each(Ecore_List *list, Ecore_For_Each function, void *user_data)
+{
+   void *value;
+
+   if (!list || !function)
+     return FALSE;
+
+   _ecore_list_first_goto(list);
+   while ((value = _ecore_list_next(list)) != NULL)
+     function(value, user_data);
+
+   return TRUE;
+}
+
+/**
+ * Find data in @p list using the compare function @p func
+ * @param list      The list.
+ * @param function  The function to test each node of @p list with
+ * @param user_data Data to match against (used by @p function)
+ * @return the first matching data node, or NULL if none match
+ */
+EAPI void *
+ecore_list_find(Ecore_List *list, Ecore_Compare_Cb function, const void *user_data)
+{
+  CHECK_PARAM_POINTER_RETURN("list", list, NULL);
+
+  return _ecore_list_find(list, function, user_data);
+}
+
+/* The real meat of finding a node via a compare cb */
+static void *
+_ecore_list_find(Ecore_List *list, Ecore_Compare_Cb function, const void *user_data)
+{
+  void *value;
+  if (!list || !function) return NULL;
+
+  _ecore_list_first_goto(list);
+  while ((value = _ecore_list_current(list)) != NULL)
+  {
+    if (!function(value, user_data)) return value;
+    ecore_list_next(list);
+  }
+
+  return NULL;
+}
+
+/**
+ * Sort data in @p list using the compare function @p compare
+ * @param list      The list.
+ * @param compare   The function to compare the data of @p list
+ * @param order     The sort direction, possible values are ECORE_SORT_MIN and
+ *                  ECORE_SORT_MAX
+ * @return          true on success
+ *
+ * This is a wrapper function for mergesort and heapsort. It
+ * tries to choose the fastest algorithm depending on the
+ * number of notes. Note: The sort may be unstable.
+ */
+EAPI int
+ecore_list_sort(Ecore_List *list, Ecore_Compare_Cb compare, char order)
+{
+   CHECK_PARAM_POINTER_RETURN("list", list, 0);
+
+   if (list->nodes < 2)
+     return 1;
+   if (list->nodes < ECORE_MERGESORT_LIMIT)
+     return ecore_list_mergesort(list, compare, order);
+   if (!ecore_list_heapsort(list, compare, order))
+     return ecore_list_mergesort(list, compare, order);
+
+   return 1;
+}
+
+/**
+ * Sort data in @p list using the compare function @p compare
+ * @param list      The list.
+ * @param compare   The function to compare the data of @p list
+ * @param order     The sort direction, possible values are ECORE_SORT_MIN and
+ *                  ECORE_SORT_MAX
+ * @return          true on success
+ *
+ * Mergesort is a stable, in-place sorting algorithm
+ */
+EAPI int
+ecore_list_mergesort(Ecore_List *list, Ecore_Compare_Cb compare, char order)
+{
+   Ecore_List_Node *node;
+
+   CHECK_PARAM_POINTER_RETURN("list", list, 0);
+   if (list->nodes < 2)
+     return 1;
+
+   if (order == ECORE_SORT_MIN)
+     order = 1;
+   else
+     order = -1;
+
+   node = _ecore_list_node_mergesort(list->first, list->nodes, compare, order);
+   list->first = node;
+
+   /* maybe there is a better way to do that but our last node has changed */
+   while (node->next)
+     node = node->next;
+   list->last = node;
+
+   _ecore_list_first_goto(list);
+
+   return 1;
+}
+
+/**
+ * Merge the @p l2 into the @p list using the compare function @p compare.
+ * Both lists need to be sorted else a corrupt list could be the result.
+ * @param list      The list.
+ * @param l2        The second list, this list will be empty after the merge
+ * @param compare   The function to compare the data of @p list and @p l2
+ * @param order     The sort direction, possible values are ECORE_SORT_MIN and
+ *                  ECORE_SORT_MAX
+ */
+EAPI void
+ecore_list_merge(Ecore_List *list, Ecore_List *l2, Ecore_Compare_Cb compare, char order)
+{
+   CHECK_PARAM_POINTER("list", list);
+   CHECK_PARAM_POINTER("l2", l2);
+
+   if (ecore_list_empty_is(l2)) return;
+
+   if (ecore_list_empty_is(list))
+     {
+       ecore_list_append_list(list, l2);
+       return;
+     }
+
+   if (order == ECORE_SORT_MIN)
+     order = 1;
+   else
+     order = -1;
+
+   list->first = _ecore_list_node_merge(list->first, l2->first, compare, order);
+
+   if ((order * compare(list->last->data, l2->last->data)) < 0)
+     list->last = l2->last;
+
+   list->nodes += l2->nodes;
+   ecore_list_init(l2);
+}
+
+/* this is the internal recrusive function for the merge sort */
+static Ecore_List_Node *
+_ecore_list_node_mergesort(Ecore_List_Node *first, int n,
+                           Ecore_Compare_Cb compare, int order)
+{
+   Ecore_List_Node *middle;
+   Ecore_List_Node *premid;
+   int mid;
+   int i;
+
+   mid = n / 2;
+
+   if (n < 2)
+     return first;
+   else if (n == 2)
+     {
+       if (compare(first->data, first->next->data) * order > 0)
+          {
+               /* swap the data */
+               void *data;
+               data = first->next->data;
+               first->next->data = first->data;
+               first->data = data;
+         }
+      return first;
+    }
+
+   /* first find the premiddle node*/
+   for (premid = first, i = 0; i < mid - 1; i++)
+     premid = premid->next;
+
+   /* split the list */
+   middle = premid->next;
+   premid->next = NULL;
+
+   /* sort the the partial lists */
+   first = _ecore_list_node_mergesort(first, mid, compare, order);
+   middle = _ecore_list_node_mergesort(middle, n - mid, compare, order);
+
+   return _ecore_list_node_merge(first, middle, compare, order);
+}
+
+/* this function is used to merge the partial sorted lists */
+static Ecore_List_Node *
+_ecore_list_node_merge(Ecore_List_Node *first, Ecore_List_Node *second,
+                       Ecore_Compare_Cb compare, int order)
+{
+   Ecore_List_Node *list;
+   Ecore_List_Node *l;
+
+   /* select the first node outside the loop, because we need to keep
+    * a pointer to it */
+   if (compare(first->data, second->data) * order > 0)
+     {
+       list = l = second;
+       second = second->next;
+     }
+   else
+     {
+       list = l = first;
+       first = first->next;
+     }
+
+   /* and now start the merging */
+   while (first && second)
+     {
+       if (compare(first->data, second->data) * order > 0)
+         {
+               l = l->next = second;
+               second = second->next;
+         }
+       else
+         {
+               l = l->next = first;
+               first = first->next;
+         }
+     }
+
+   /* append the rest or set it to NULL */
+   if (first)
+     l->next = first;
+   else if (second)
+     l->next = second;
+   else
+     l->next = NULL;
+
+   return list;
+}
+
+/**
+ * Sort data in @p list using the compare function @p compare
+ * @param list      The list.
+ * @param compare   The function to compare the data of @p list
+ * @param order     The sort direction, possible values are ECORE_SORT_MIN and
+ *                  ECORE_SORT_MAX
+ * @return          true on success
+ *
+ * Heapsort is a unstable sorting algorithm, it needs to allocate extra memomry,
+ * but there for it is for a great number of nodes faster than mergesort
+ */
+EAPI int
+ecore_list_heapsort(Ecore_List *list, Ecore_Compare_Cb compare, char order)
+{
+   Ecore_Sheap *heap;
+   Ecore_List_Node *node;
+   void *data;
+
+   CHECK_PARAM_POINTER_RETURN("list", list, 0);
+   /*
+    * Push the data into a heap.
+    */
+   heap = ecore_sheap_new(compare, list->nodes);
+   if (!heap)
+     return 0;
+
+   ecore_sheap_order_set(heap, order);
+   _ecore_list_first_goto(list);
+   while ((data = _ecore_list_next(list)))
+     {
+       ecore_sheap_insert(heap, data);
+     }
+
+   /*
+    * Extract in sorted order.
+    */
+   node = list->first;
+   while (node)
+     {
+       node->data = ecore_sheap_extract(heap);
+       node = node->next;
+     }
+
+   ecore_sheap_destroy(heap);
+
+   _ecore_list_first_goto(list);
+   return 1;
+}
+
+/* Initialize a node to starting values */
+EAPI int
+ecore_list_node_init(Ecore_List_Node *node)
+{
+   CHECK_PARAM_POINTER_RETURN("node", node, FALSE);
+
+   node->next = NULL;
+   node->data = NULL;
+
+   return TRUE;
+}
+
+/**
+@defgroup Ecore_Data_List_Node_Group List Node Functions
+
+Functions that are used in the creation, maintenance and destruction of
+Ecore_List nodes.
+*/
+
+/**
+ * Allocates and initializes a new list node.
+ * @return  A new Ecore_List_Node on success, @c NULL otherwise.
+ * @ingroup Ecore_Data_List_Node_Group
+ */
+EAPI Ecore_List_Node *
+ecore_list_node_new()
+{
+   Ecore_List_Node *new_node;
+
+   new_node = malloc(sizeof(Ecore_List_Node));
+
+   if (!ecore_list_node_init(new_node))
+     {
+       FREE(new_node);
+       return NULL;
+     }
+
+   return new_node;
+}
+
+/**
+ * Calls the function to free the data and the node.
+ * @param   node      Node to destroy.
+ * @param   free_func Function to call if @p node points to data to free.
+ * @return  @c TRUE.
+ * @ingroup Ecore_Data_List_Node_Group
+ */
+EAPI int
+ecore_list_node_destroy(Ecore_List_Node *node, Ecore_Free_Cb free_func)
+{
+   CHECK_PARAM_POINTER_RETURN("node", node, FALSE);
+
+   if (free_func && node->data)
+     free_func(node->data);
+
+   FREE(node);
+
+   return TRUE;
+}
+
+/**
+ * @defgroup Ecore_Data_DList_Creation_Group Doubly Linked List Creation/Destruction Functions
+ *
+ * Functions used to create, initialize and destroy @c Ecore_DLists.
+ */
+
+/**
+ * Creates and initialises a new doubly linked list.
+ * @return  A new initialised doubly linked list on success, @c NULL
+ *          on failure.
+ * @ingroup Ecore_Data_DList_Creation_Group
+ */
+EAPI Ecore_DList *
+ecore_dlist_new()
+{
+   Ecore_DList *list = NULL;
+
+   list = (Ecore_DList *)malloc(sizeof(Ecore_DList));
+   if (!list)
+     return NULL;
+
+   if (!ecore_dlist_init(list))
+     {
+       IF_FREE(list);
+       return NULL;
+     }
+
+   return list;
+}
+
+/**
+ * Initialises a list to some sane starting values.
+ * @param   list The doubly linked list to initialise.
+ * @return  @c TRUE if successful, @c FALSE if an error occurs.
+ * @ingroup Ecore_Data_DList_Creation_Group
+ */
+EAPI int
+ecore_dlist_init(Ecore_DList *list)
+{
+   CHECK_PARAM_POINTER_RETURN("list", list, FALSE);
+
+   memset(list, 0, sizeof(Ecore_DList));
+
+   return TRUE;
+}
+
+/**
+ * Frees a doubly linked list and all of its nodes.
+ * @param   list The doubly linked list to be freed.
+ * @ingroup Ecore_Data_DList_Creation_Group
+ */
+EAPI void
+ecore_dlist_destroy(Ecore_DList *list)
+{
+   void *data;
+   CHECK_PARAM_POINTER("list", list);
+
+   while (list->first)
+     {
+       data = _ecore_dlist_first_remove(list);
+       if (list->free_func)
+         list->free_func(data);
+     }
+
+   FREE(list);
+}
+
+/**
+ * Sets the function used for freeing data stored in a doubly linked list.
+ * @param   list      The doubly linked list that will use this function when
+ *                    nodes are destroyed.
+ * @param   free_func The function that will free the key data
+ * @return  @c TRUE on success, @c FALSE on failure.
+ * @ingroup Ecore_Data_DList_Creation_Group
+ */
+EAPI int
+ecore_dlist_free_cb_set(Ecore_DList *list, Ecore_Free_Cb free_func)
+{
+   CHECK_PARAM_POINTER_RETURN("list", list, FALSE);
+
+   return ecore_list_free_cb_set(ECORE_LIST(list), free_func);
+}
+
+/**
+ * Returns whether there is anything in the given doubly linked list.
+ * @param  list The given doubly linked list.
+ * @return @c TRUE if there are nodes, @c FALSE otherwise.
+ */
+EAPI int
+ecore_dlist_empty_is(Ecore_DList *list)
+{
+   CHECK_PARAM_POINTER_RETURN("list", list, FALSE);
+
+   return ecore_list_empty_is(ECORE_LIST(list));
+}
+
+/**
+ * Retrieves the index of the current node of the given doubly linked list.
+ * @param  list The given doubly linked list.
+ * @return The index of the current node.
+ */
+EAPI inline int
+ecore_dlist_index(Ecore_DList *list)
+{
+   CHECK_PARAM_POINTER_RETURN("list", list, FALSE);
+
+   return ecore_list_index(ECORE_LIST(list));
+}
+
+/**
+ * @defgroup Ecore_Data_DList_Add_Item_Group Doubly Linked List Adding Functions
+ *
+ * Functions that are used to add nodes to an Ecore_DList.
+ */
+
+/**
+ * Appends data to the given doubly linked list.
+ * @param   list The given doubly linked list.
+ * @param   data The data to append.
+ * @return  @c TRUE if the data is successfully appended, @c FALSE otherwise.
+ * @ingroup Ecore_Data_DList_Add_Item_Group
+ */
+EAPI int
+ecore_dlist_append(Ecore_DList *list, void *data)
+{
+   int ret;
+   Ecore_DList_Node *prev;
+   Ecore_DList_Node *node;
+
+   CHECK_PARAM_POINTER_RETURN("list", list, FALSE);
+
+   node = ecore_dlist_node_new();
+   ECORE_LIST_NODE(node)->data = data;
+
+   prev = ECORE_DLIST_NODE(ECORE_LIST(list)->last);
+   ret = _ecore_list_append_0(ECORE_LIST(list), ECORE_LIST_NODE(node));
+   if (ret)
+     node->previous = prev;
+
+   return ret;
+}
+
+/**
+ * Adds data to the very beginning of the given doubly linked list.
+ * @param   list The given doubly linked list.
+ * @param   data The data to prepend.
+ * @return  @c TRUE if the data is successfully prepended, @c FALSE otherwise.
+ * @ingroup Ecore_Data_DList_Add_Item_Group
+ */
+EAPI int
+ecore_dlist_prepend(Ecore_DList *list, void *data)
+{
+   int ret;
+   Ecore_DList_Node *prev;
+   Ecore_DList_Node *node;
+
+   CHECK_PARAM_POINTER_RETURN("list", list, FALSE);
+
+   node = ecore_dlist_node_new();
+   ECORE_LIST_NODE(node)->data = data;
+
+   prev = ECORE_DLIST_NODE(ECORE_LIST(list)->first);
+   ret = _ecore_list_prepend_0(ECORE_LIST(list), ECORE_LIST_NODE(node));
+   if (ret && prev)
+     prev->previous = node;
+
+   return ret;
+}
+
+/**
+ * Inserts data at the current point in the given doubly linked list.
+ * @param   list The given doubly linked list.
+ * @param   data The data to be inserted.
+ * @return  @c TRUE on success, @c FALSE otherwise.
+ * @ingroup Ecore_Data_DList_Add_Item_Group
+ */
+EAPI int
+ecore_dlist_insert(Ecore_DList *list, void *data)
+{
+   int ret = TRUE;
+   Ecore_DList_Node *prev;
+   Ecore_DList_Node *node;
+
+   CHECK_PARAM_POINTER_RETURN("list", list, FALSE);
+
+   /*
+    * Identify and shortcut the end cases.
+    */
+   if (!ECORE_LIST(list)->current)
+     return ecore_dlist_append(list, data);
+   if (ECORE_LIST(list)->current == ECORE_LIST(list)->first)
+     return ecore_dlist_prepend(list, data);
+
+   node = ecore_dlist_node_new();
+   ECORE_LIST_NODE(node)->data = data;
+
+   /* Setup the fields of the new node */
+   ECORE_LIST_NODE(node)->next = ECORE_LIST(list)->current;
+
+   /* And hook the node into the list */
+   prev = ECORE_DLIST_NODE(ECORE_LIST(list)->current)->previous;
+   ECORE_LIST_NODE(prev)->next = ECORE_LIST_NODE(node);
+   ECORE_DLIST_NODE(ECORE_LIST(list)->current)->previous = node;
+   node->previous = prev;
+
+   /* Now move the current item to the inserted item */
+   ECORE_LIST(list)->current = ECORE_LIST_NODE(node);
+   ECORE_LIST(list)->nodes++;
+
+   return ret;
+}
+
+/**
+ * Appends a list to the given doubly linked list.
+ * @param   list The given doubly linked list.
+ * @param   append The list to append.
+ * @return  @c TRUE if the data is successfully appended, @c FALSE otherwise.
+ * @ingroup Ecore_Data_DList_Add_Item_Group
+ */
+EAPI int
+ecore_dlist_append_list(Ecore_DList *list, Ecore_DList *append)
+{
+   CHECK_PARAM_POINTER_RETURN("list", list, FALSE);
+   CHECK_PARAM_POINTER_RETURN("append", append, FALSE);
+
+   if (ecore_dlist_empty_is(append)) return TRUE;
+
+   if (ecore_dlist_empty_is(list))
+     {
+       list->first = append->first;
+       list->current = NULL;
+       list->last = append->last;
+       list->nodes = append->nodes;
+     }
+   else
+     {
+       list->last->next = append->first;
+       ECORE_DLIST_NODE(append->first)->previous = ECORE_DLIST_NODE(list->last);
+       list->last = append->last;
+       list->nodes += append->nodes;
+     }
+   ecore_dlist_init(append);
+   return TRUE;
+}
+
+/**
+ * Adds a list to the very beginning of the given doubly linked list.
+ * @param   list The given doubly linked list.
+ * @param   prepend The list to prepend.
+ * @return  @c TRUE if the data is successfully prepended, @c FALSE otherwise.
+ * @ingroup Ecore_Data_DList_Add_Item_Group
+ */
+EAPI int
+ecore_dlist_prepend_list(Ecore_DList *list, Ecore_DList *prepend)
+{
+   CHECK_PARAM_POINTER_RETURN("list", list, FALSE);
+   CHECK_PARAM_POINTER_RETURN("prepend", prepend, FALSE);
+
+   if (ecore_dlist_empty_is(prepend)) return TRUE;
+
+   if (ecore_dlist_empty_is(list))
+     {
+       list->first = prepend->first;
+       list->current = NULL;
+       list->last = prepend->last;
+       list->nodes = prepend->nodes;
+     }
+   else
+     {
+       prepend->last->next = list->first;
+       ECORE_DLIST_NODE(list->first)->previous = ECORE_DLIST_NODE(prepend->last);
+       list->first = prepend->first;
+       list->nodes += prepend->nodes;
+       list->index += prepend->nodes;
+     }
+   ecore_dlist_init(prepend);
+   return TRUE;
+}
+
+/**
+ * @defgroup Ecore_Data_DList_Remove_Item_Group Doubly Linked List Removing Functions
+ *
+ * Functions that remove nodes from an @c Ecore_DList.
+ */
+
+/**
+ * Removes the current item from the given doubly linked list.
+ * @param   list The given doubly linked list.
+ * @return  A pointer to the removed data on success, @c NULL otherwise.
+ * @ingroup Ecore_Data_DList_Remove_Item_Group
+ */
+EAPI void *
+ecore_dlist_remove(Ecore_DList *list)
+{
+   void *ret;
+   Ecore_List *l2 = ECORE_LIST(list);
+   Ecore_DList_Node *node;
+
+   CHECK_PARAM_POINTER_RETURN("list", list, NULL);
+
+   if (l2->current)
+     {
+       node = ECORE_DLIST_NODE(list->current->next);
+       if (node)
+         node->previous = ECORE_DLIST_NODE(l2->current)->previous;
+     }
+   ret = _ecore_list_remove_0(list);
+
+   return ret;
+}
+
+/**
+ * Removes the first item from the given doubly linked list.
+ * @param   list The given doubly linked list.
+ * @return  A pointer to the removed data on success, @c NULL on failure.
+ * @ingroup Ecore_Data_DList_Remove_Item_Group
+ */
+EAPI void *
+ecore_dlist_first_remove(Ecore_DList *list)
+{
+   void *ret;
+
+   CHECK_PARAM_POINTER_RETURN("list", list, NULL);
+
+   ret = _ecore_dlist_first_remove(list);
+
+   return ret;
+}
+
+/**
+ * Removes and frees the data at the current position in the given doubly
+ * linked list.
+ * @param   list The given doubly linked list.
+ * @return  @c TRUE on success, @c FALSE otherwise.
+ * @ingroup Ecore_Data_DList_Remove_Item_Group
+ */
+EAPI int
+ecore_dlist_remove_destroy(Ecore_DList *list)
+{
+   void *data;
+
+   CHECK_PARAM_POINTER_RETURN("list", list, FALSE);
+
+   data = ecore_dlist_remove(list);
+   if (!data)
+     return FALSE;
+
+   if (list->free_func)
+     list->free_func(data);
+
+   return TRUE;
+}
+
+static void *
+_ecore_dlist_first_remove(Ecore_DList *list)
+{
+   void *ret;
+
+   if (!list)
+     return NULL;
+
+   ret = _ecore_list_first_remove(list);
+   if (ret && ECORE_LIST(list)->first)
+     ECORE_DLIST_NODE(ECORE_LIST(list)->first)->previous = NULL;
+
+   return ret;
+}
+
+/**
+ * Removes the last item from the given doubly linked list.
+ * @param   list The given doubly linked list.
+ * @return  A pointer to the removed data on success, @c NULL otherwise.
+ * @ingroup Ecore_Data_DList_Remove_Item_Group
+ */
+EAPI void *
+ecore_dlist_last_remove(Ecore_DList *list)
+{
+   void *ret;
+   Ecore_List_Node *node;
+
+   CHECK_PARAM_POINTER_RETURN("list", list, NULL);
+
+   if (ecore_list_empty_is(list))
+     return NULL;
+
+   node = list->last;
+   list->last = ECORE_LIST_NODE(ECORE_DLIST_NODE(node)->previous);
+   if (list->last)
+     list->last->next = NULL;
+   if (list->first == node)
+     list->first = NULL;
+   if (list->current == node)
+     list->current = NULL;
+
+   ret = node->data;
+   ecore_list_node_destroy(node, NULL);
+
+   list->nodes--;
+   if (list->index >= list->nodes)
+     list->index--;
+
+   return ret;
+}
+
+/**
+ * Moves the current item to the index number in the given doubly linked list.
+ * @param  list  The given doubly linked list.
+ * @param  index The position to move the current item
+ * @return The node at specified index on success, @c NULL on error.
+ */
+EAPI void *
+ecore_dlist_index_goto(Ecore_DList *list, int index)
+{
+   void *ret;
+
+   CHECK_PARAM_POINTER_RETURN("list", list, NULL);
+
+   ret = _ecore_dlist_index_goto(list, index);
+
+   return ret;
+}
+
+/* This is the non-threadsafe version, use this inside internal functions that
+ * already lock the list */
+static void *
+_ecore_dlist_index_goto(Ecore_DList *list, int index)
+{
+   int i, increment;
+
+   if (!list)
+     return NULL;
+
+   if (ecore_list_empty_is(ECORE_LIST(list)))
+     return NULL;
+
+   if (index > ecore_list_count(ECORE_LIST(list)) || index < 0)
+     return NULL;
+
+   if (ECORE_LIST(list)->index >= ECORE_LIST(list)->nodes)
+     _ecore_list_last_goto(ECORE_LIST(list));
+
+   if (index < ECORE_LIST(list)->index)
+     increment = -1;
+   else
+     increment = 1;
+
+   for (i = ECORE_LIST(list)->index; i != index; i += increment)
+     {
+       if (increment > 0)
+         _ecore_list_next(list);
+       else
+         _ecore_dlist_previous(list);
+     }
+
+   return _ecore_list_current(list);
+}
+
+/**
+ * @brief Move the current item to the node that contains data
+ * @param list: the list to move the current item in
+ * @param data: the data to find and set the current item to
+ *
+ * @return Returns specified data on success, NULL on error
+ */
+EAPI void *
+ecore_dlist_goto(Ecore_DList *list, void *data)
+{
+   void *ret;
+
+   CHECK_PARAM_POINTER_RETURN("list", list, NULL);
+
+   ret = _ecore_list_goto(ECORE_LIST(list), data);
+
+   return ret;
+}
+
+/**
+ * @brief Move the current pointer to the first item in the list
+ * @param list: the list to change the current to the first item
+ *
+ * @return Returns a pointer to the first item on success, NULL on failure.
+ */
+EAPI void *
+ecore_dlist_first_goto(Ecore_DList *list)
+{
+   void *ret;
+
+   CHECK_PARAM_POINTER_RETURN("list", list, NULL);
+
+   ret = _ecore_list_first_goto(list);
+
+   return ret;
+}
+
+/**
+ * @brief Move the pointer to the current item to the last item
+ * @param list: the list to move the current item pointer to the last
+ * @return Returns a pointer to the last item in the list , NULL if empty.
+ */
+EAPI void *
+ecore_dlist_last_goto(Ecore_DList *list)
+{
+   void *ret;
+
+   CHECK_PARAM_POINTER_RETURN("list", list, NULL);
+
+   ret = _ecore_list_last_goto(ECORE_LIST(list));
+
+   return ret;
+}
+
+/**
+ * @brief Return the data in the current list item
+ * @param list: the list to the return the current data
+ * @return Returns value of the current data item, NULL if no current item
+ */
+EAPI void *
+ecore_dlist_current(Ecore_DList *list)
+{
+   void *ret;
+
+   ret = _ecore_list_current(ECORE_LIST(list));
+
+   return ret;
+}
+
+/**
+ * @brief Move to the next item in the list and return current item
+ * @param list: the list to move to the next item in.
+ * @return Returns data in the current list node, or NULL on error
+ */
+EAPI void *
+ecore_dlist_next(Ecore_DList *list)
+{
+   void *data;
+
+   data = _ecore_list_next(list);
+
+   return data;
+}
+
+/**
+ * @brief Move to the previous item and return current item
+ * @param list: the list to move to the previous item in.
+ * @return Returns data in the current list node, or NULL on error
+ */
+EAPI void *
+ecore_dlist_previous(Ecore_DList *list)
+{
+   void *data;
+
+   data = _ecore_dlist_previous(list);
+
+   return data;
+}
+
+static void *
+_ecore_dlist_previous(Ecore_DList *list)
+{
+   void *data = NULL;
+
+   if (!list)
+     return NULL;
+
+   if (ECORE_LIST(list)->current)
+     {
+       data = ECORE_LIST(list)->current->data;
+       ECORE_LIST(list)->current = ECORE_LIST_NODE(ECORE_DLIST_NODE(
+                                                                    ECORE_LIST(list)->current)->previous);
+       ECORE_LIST(list)->index--;
+     }
+   else
+     _ecore_list_last_goto(ECORE_LIST(list));
+
+   return data;
+}
+
+/**
+ * @brief Remove all nodes from the list.
+ * @param list: the list to remove all nodes from
+ *
+ * @return Returns TRUE on success, FALSE on errors
+ */
+EAPI int
+ecore_dlist_clear(Ecore_DList *list)
+{
+   CHECK_PARAM_POINTER_RETURN("list", list, FALSE);
+
+   ecore_list_clear(ECORE_LIST(list));
+
+   return TRUE;
+}
+
+/**
+ * Sort data in @p list using the compare function @p compare
+ * @param list      The list.
+ * @param compare   The function to compare the data of @p list
+ * @param order     The sort direction, possible values are ECORE_SORT_MIN and
+ *                  ECORE_SORT_MAX
+ * @return          true on success
+ *
+ * This is a wrapper function for mergesort and heapsort. It
+ * tries to choose the fastest algorithm depending on the
+ * number of notes. Note: The sort may be unstable.
+ */
+EAPI int
+ecore_dlist_sort(Ecore_List *list, Ecore_Compare_Cb compare, char order)
+{
+   CHECK_PARAM_POINTER_RETURN("list", list, 0);
+
+   if (list->nodes < 2)
+     return 1;
+   if (list->nodes < ECORE_MERGESORT_LIMIT)
+     return ecore_dlist_mergesort(list, compare, order);
+   if (!ecore_dlist_heapsort(list, compare, order))
+     return ecore_dlist_mergesort(list, compare, order);
+
+   return 1;
+}
+
+/**
+ * Sort data in @p list using the compare function @p compare
+ * @param list      The list.
+ * @param compare   The function to compare the data of @p list
+ * @param order     The sort direction, possible values are ECORE_SORT_MIN and
+ *                  ECORE_SORT_MAX
+ * @return          true on success
+ *
+ * Mergesort is a stable, in-place sorting algorithm
+ */
+EAPI int
+ecore_dlist_mergesort(Ecore_DList *list, Ecore_Compare_Cb compare, char order)
+{
+   Ecore_List_Node *node;
+
+   CHECK_PARAM_POINTER_RETURN("list", list, 0);
+   if (list->nodes < 2)
+     return 1;
+
+   if (order == ECORE_SORT_MIN)
+     order = 1;
+   else
+     order = -1;
+
+   node = _ecore_dlist_node_mergesort(list->first, list->nodes, compare, order);
+   list->first = node;
+
+   /* maybe there is a better way to do that but our last node has changed */
+   while (node->next)
+     node = node->next;
+   list->last = node;
+
+   _ecore_list_first_goto(list);
+
+   return 1;
+}
+
+/**
+ * Merge the @p l2 into the @p list using the compare function @p compare.
+ * Both lists need to be sorted else a corrupt list could be the result.
+ * @param list      The list.
+ * @param l2        The second list, this list will be empty after the merge
+ * @param compare   The function to compare the data of @p list and @p l2
+ * @param order     The sort direction, possible values are ECORE_SORT_MIN and
+ *                  ECORE_SORT_MAX
+ */
+EAPI void
+ecore_dlist_merge(Ecore_DList *list, Ecore_DList *l2, Ecore_Compare_Cb compare, char order)
+{
+   CHECK_PARAM_POINTER("list", list);
+   CHECK_PARAM_POINTER("l2", l2);
+
+   if (ecore_dlist_empty_is(l2)) return;
+
+   if (ecore_dlist_empty_is(list))
+     {
+       ecore_dlist_append_list(list, l2);
+       return;
+     }
+
+   if (order == ECORE_SORT_MIN)
+     order = 1;
+   else
+     order = -1;
+
+   list->first = _ecore_dlist_node_merge(list->first, l2->first, compare, order);
+
+   if ((order * compare(list->last->data, l2->last->data)) < 0)
+     list->last = l2->last;
+
+   list->nodes += l2->nodes;
+   ecore_dlist_init(l2);
+}
+
+/* this is the internal recrusive function for the merge sort */
+static Ecore_List_Node *
+_ecore_dlist_node_mergesort(Ecore_List_Node *first, int n,
+                           Ecore_Compare_Cb compare, int order)
+{
+   Ecore_List_Node *middle;
+   Ecore_List_Node *premid;
+   int mid;
+   int i;
+
+   mid = n/2;
+
+   if (n < 2)
+     return first;
+   else if (n == 2)
+     {
+       if (compare(first->data, first->next->data) * order > 0)
+          {
+               /* swap the data */
+               void *data;
+               data = first->next->data;
+               first->next->data = first->data;
+               first->data = data;
+         }
+      return first;
+    }
+
+   /* first find the premiddle node*/
+   for (premid = first, i = 0; i < mid - 1; i++)
+     premid = premid->next;
+
+   /* split the list */
+   middle = premid->next;
+   premid->next = NULL;
+   ECORE_DLIST_NODE(middle)->previous = NULL;
+
+   /* sort the the partial lists */
+   first = _ecore_dlist_node_mergesort(first, mid, compare, order);
+   middle = _ecore_dlist_node_mergesort(middle, n - mid, compare, order);
+
+   return _ecore_dlist_node_merge(first, middle, compare, order);
+}
+
+/* this function is used to merge the partial sorted lists */
+static Ecore_List_Node *
+_ecore_dlist_node_merge(Ecore_List_Node *first, Ecore_List_Node *second,
+                       Ecore_Compare_Cb compare, int order)
+{
+   Ecore_List_Node *list;
+   Ecore_List_Node *l;
+
+   /* select the first node outside the loop, because we need to keep
+    * a pointer to it */
+   if (compare(first->data, second->data) * order > 0)
+     {
+       list = l = second;
+       second = second->next;
+     }
+   else
+     {
+       list = l = first;
+       first = first->next;
+     }
+
+   /* and now start the merging */
+   while (first && second)
+     {
+       if (compare(first->data, second->data) * order > 0)
+         {
+               ECORE_DLIST_NODE(second)->previous = ECORE_DLIST_NODE(l);
+               l = l->next = second;
+               second = second->next;
+         }
+       else
+         {
+               ECORE_DLIST_NODE(first)->previous = ECORE_DLIST_NODE(l);
+               l = l->next = first;
+               first = first->next;
+         }
+     }
+
+   /* append the rest or set it to NULL */
+   if (first)
+     {
+       ECORE_DLIST_NODE(first)->previous = ECORE_DLIST_NODE(l);
+        l->next = first;
+     }
+   else if (second)
+     {
+       ECORE_DLIST_NODE(second)->previous = ECORE_DLIST_NODE(l);
+       l->next = second;
+     }
+   else
+     l->next = NULL;
+
+   return list;
+}
+
+/*
+ * @brief Initialize a node to sane starting values
+ * @param node: the node to initialize
+ * @return Returns TRUE on success, FALSE on errors
+ */
+EAPI int
+ecore_dlist_node_init(Ecore_DList_Node *node)
+{
+   int ret;
+
+   CHECK_PARAM_POINTER_RETURN("node", node, FALSE);
+
+   ret = ecore_list_node_init(ECORE_LIST_NODE(node));
+   if (ret)
+     node->previous = NULL;
+
+   return ret;
+}
+
+/*
+ * @brief Allocate and initialize a new list node
+ * @return Returns NULL on error, new list node on success
+ */
+EAPI Ecore_DList_Node *
+ecore_dlist_node_new()
+{
+   Ecore_DList_Node *new_node;
+
+   new_node = malloc(sizeof(Ecore_DList_Node));
+
+   if (!new_node)
+     return NULL;
+
+   if (!ecore_dlist_node_init(new_node))
+     {
+       FREE(new_node);
+       return NULL;
+     }
+
+   return new_node;
+}
+
+/*
+ * @brief Call the data's free callback function, then free the node
+ * @param node: the node to be freed
+ * @param free_func: the callback function to execute on the data
+ * @return Returns TRUE on success, FALSE on error
+ */
+EAPI int
+ecore_dlist_node_destroy(Ecore_DList_Node * node, Ecore_Free_Cb free_func)
+{
+   CHECK_PARAM_POINTER_RETURN("node", node, FALSE);
+
+   return ecore_list_node_destroy(ECORE_LIST_NODE(node), free_func);
+}
diff --git a/src/tests/ecore_sheap.c b/src/tests/ecore_sheap.c
new file mode 100644 (file)
index 0000000..a39d358
--- /dev/null
@@ -0,0 +1,472 @@
+/*
+ * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "Ecore_Data.h"
+
+#define HEAP_INCREMENT 4096
+
+#define PARENT(i) (i / 2)
+#define LEFT(i) (2 * i)
+#define RIGHT(i) (2 * i + 1)
+
+static void _ecore_sheap_heapify(Ecore_Sheap *heap, int i);
+static void _ecore_sheap_update_data(Ecore_Sheap *heap);
+
+/**
+ * Allocate and initialize a new binary heap
+ * @param compare The function for comparing keys, NULL for direct comparison
+ * @param size    The number of elements to allow in the heap
+ * @return A pointer to the newly allocated binary heap on success, NULL on
+ * failure.
+ */
+EAPI Ecore_Sheap *
+ecore_sheap_new(Ecore_Compare_Cb compare, int size)
+{
+   Ecore_Sheap *heap = NULL;
+
+   heap = (Ecore_Sheap *)malloc(sizeof(Ecore_Sheap));
+   if (!heap)
+     return NULL;
+   memset(heap, 0, sizeof(Ecore_Sheap));
+
+   if (!ecore_sheap_init(heap, compare, size))
+     {
+       FREE(heap);
+       return NULL;
+     }
+
+   return heap;
+}
+
+/**
+ * Initialize a binary heap to default values
+ * @param heap    The heap to initialize
+ * @param compare The function for comparing keys, NULL for direct comparison
+ * @param size    The number of elements to allow in the heap
+ * @return        TRUE on success, FALSE on failure
+ */
+EAPI int
+ecore_sheap_init(Ecore_Sheap *heap, Ecore_Compare_Cb compare, int size)
+{
+   CHECK_PARAM_POINTER_RETURN("heap", heap, FALSE);
+
+   heap->space = size;
+   if (!compare)
+     heap->compare = ecore_direct_compare;
+   else
+     heap->compare = compare;
+   heap->order = ECORE_SORT_MIN;
+
+   heap->data = (void **)malloc(heap->space * sizeof(void *));
+   if (!heap->data)
+     return FALSE;
+   memset(heap->data, 0, heap->space * sizeof(void *));
+
+   return TRUE;
+}
+
+/**
+ * Free up the memory used by the heap
+ *
+ * Frees the memory used by @a heap, calls the destroy function on each data
+ * item if necessary.
+ *
+ * @param  heap The heap to be freed
+ */
+EAPI void
+ecore_sheap_destroy(Ecore_Sheap *heap)
+{
+   int i;
+
+   CHECK_PARAM_POINTER("heap", heap);
+
+   /*
+    * Free data in heap
+    */
+   if (heap->free_func)
+     for (i = 0; i < heap->size; i++)
+       heap->free_func(heap->data[i]);
+
+   FREE(heap->data);
+
+   FREE(heap);
+}
+
+/**
+ * Set the function for freeing data.
+ * @param  heap      The heap that will use this function when nodes are
+ *                   destroyed.
+ * @param  free_func The function that will free the key data.
+ * @return @c TRUE on successful set, @c FALSE otherwise.
+ */
+EAPI int
+ecore_sheap_free_cb_set(Ecore_Sheap *heap, Ecore_Free_Cb free_func)
+{
+   CHECK_PARAM_POINTER_RETURN("heap", heap, FALSE);
+
+   heap->free_func = free_func;
+
+   return TRUE;
+}
+
+/**
+ * Insert new data into the heap.
+ * @param  heap The heap to insert @a data.
+ * @param  data The data to add to @a heap.
+ * @return TRUE on success, NULL on failure. Increases the size of the heap if
+ *         it becomes larger than available space.
+ */
+EAPI int
+ecore_sheap_insert(Ecore_Sheap *heap, void *data)
+{
+   int i;
+   void *temp;
+   int parent;
+   int position;
+
+   CHECK_PARAM_POINTER_RETURN("heap", heap, FALSE);
+
+   /*
+    * Increase the size of the allocated data area if there isn't enough
+    * space available to add this data
+    */
+   if (heap->size >= heap->space)
+     return FALSE;
+
+   heap->sorted = FALSE;
+
+   /*
+    * Place the data at the end of the heap initially. Then determine the
+    * parent and position in the array of it's parent.
+    */
+   heap->data[heap->size] = data;
+   position = heap->size;
+   heap->size++;
+   i = heap->size;
+   parent = PARENT(i) - 1;
+
+   /*
+    * Check the order of the heap to decide where to place the inserted
+    * data. The loop is placed inside the if statement to reduce the
+    * number of branching decisions that must be predicted.
+    */
+   if (heap->order == ECORE_SORT_MIN)
+     {
+       while ((position > 0) && heap->compare(heap->data[parent],
+                                              heap->data[position]) > 0)
+         {
+
+            /*
+             * Swap the data with it's parents to move it up in
+             * the heap.
+             */
+            temp = heap->data[position];
+            heap->data[position] = heap->data[parent];
+            heap->data[parent] = temp;
+
+            /*
+             * Now determine the new position for the next
+             * iteration of the loop, as well as it's parents
+             * position.
+             */
+            i = PARENT(i);
+            position = i - 1;
+            parent = PARENT(i) - 1;
+         }
+     }
+   else
+     {
+       while ((position > 0) && heap->compare(heap->data[parent],
+                                              heap->data[position]) < 0)
+         {
+
+            /*
+             * Swap the data with it's parents to move it up in
+             * the heap.
+             */
+            temp = heap->data[position];
+            heap->data[position] = heap->data[PARENT(i) - 1];
+            heap->data[PARENT(i) - 1] = temp;
+
+            /*
+             * Now determine the new position for the next
+             * iteration of the loop, as well as it's parents
+             * position.
+             */
+            i = PARENT(i);
+            position = i - 1;
+            parent = PARENT(i) - 1;
+         }
+     }
+
+   return TRUE;
+}
+
+/**
+ * Extract the item at the top of the heap
+ * @param  heap The heap to remove the top item
+ * @return The top item of the heap on success, NULL on failure.
+ * @note   The extract function maintains the heap properties after the
+ *         extract.
+ */
+EAPI void *
+ecore_sheap_extract(Ecore_Sheap *heap)
+{
+   void *extreme;
+
+   if (heap->size < 1)
+     return NULL;
+
+   heap->sorted = FALSE;
+
+   extreme = heap->data[0];
+   heap->size--;
+   heap->data[0] = heap->data[heap->size];
+
+   _ecore_sheap_heapify(heap, 1);
+
+   return extreme;
+}
+
+/**
+ * Examine the item at the top of the heap
+ * @param  heap The heap to examine the top item
+ * @return The top item of the heap on success, NULL on failure.
+ * @note   The function does not alter the heap.
+ */
+EAPI void *
+ecore_sheap_extreme(Ecore_Sheap *heap)
+{
+   if (heap->size < 1)
+     return NULL;
+
+   return heap->data[0];
+}
+
+/**
+ * Change the value of the specified item in the heap
+ * @param heap   The heap to search for the item to change
+ * @param item   The item in the heap to change
+ * @param newval The new value assigned to the item in the heap
+ * @return       TRUE on success, FALSE on failure.
+ * @note         The heap does not free the old data since it must be passed
+ *               in, so the caller can perform the free if desired.
+ */
+EAPI int
+ecore_sheap_change(Ecore_Sheap *heap, void *item, void *newval)
+{
+   int i;
+
+   CHECK_PARAM_POINTER_RETURN("heap", heap, FALSE);
+
+   for (i = 0; i < heap->size && heap->compare(heap->data[i], item); i++);
+
+   if (i < heap->size)
+     heap->data[i] = newval;
+   else
+     return FALSE;
+
+   /*
+    * FIXME: This is not the correct procedure when a change occurs.
+    */
+   _ecore_sheap_heapify(heap, 1);
+
+   return TRUE;
+}
+
+/**
+ * Change the comparison function for the heap
+ * @param  heap    The heap to change comparison function
+ * @param  compare The new function for comparing nodes
+ * @return TRUE on success, FALSE on failure.
+ *
+ * The comparison function is changed to @compare and the heap is heapified
+ * by the new comparison.
+ */
+EAPI int
+ecore_sheap_compare_set(Ecore_Sheap *heap, Ecore_Compare_Cb compare)
+{
+   CHECK_PARAM_POINTER_RETURN("heap", heap, FALSE);
+
+   if (!compare)
+     heap->compare = ecore_direct_compare;
+   else
+     heap->compare = compare;
+
+   _ecore_sheap_update_data(heap);
+
+   return TRUE;
+}
+
+/**
+ * Change the order of the heap
+ * @param  heap  The heap to change the order
+ * @param  order The new order of the heap
+ *
+ * Changes the heap order of @heap and re-heapifies the data to this new
+ * order. The default order is a min heap.
+ */
+EAPI void
+ecore_sheap_order_set(Ecore_Sheap *heap, char order)
+{
+   CHECK_PARAM_POINTER("heap", heap);
+
+   heap->order = order;
+
+   _ecore_sheap_update_data(heap);
+}
+
+/**
+ * Sort the data in the heap
+ * @param  heap The heap to be sorted
+ *
+ * Sorts the data in the heap into the order that is used for the heap's
+ * data.
+ */
+EAPI void
+ecore_sheap_sort(Ecore_Sheap *heap)
+{
+   int i = 0;
+   void **new_data;
+
+   CHECK_PARAM_POINTER("heap", heap);
+
+   new_data = (void **)malloc(heap->size * sizeof(void *));
+
+   /*
+    * Extract the heap and insert into the new data array in order.
+    */
+   while (heap->size > 0)
+     new_data[i++] = ecore_sheap_extract(heap);
+
+   /*
+    * Free the old data array and update the heap with the new data, also
+    * mark as sorted.
+    */
+   FREE(heap->data);
+   heap->data = new_data;
+   heap->size = i;
+   heap->sorted = TRUE;
+}
+
+/*
+ * Access the item at the ith position in the heap
+ * @param  heap The heap to access the internal data
+ * @param  i    The index of the data within the heap
+ * @return The data located at the ith position within @heap on success,
+ *         NULL on failure.
+ * @note   The data is guaranteed to be in sorted order.
+ */
+EAPI inline void *
+ecore_sheap_item(Ecore_Sheap *heap, int i)
+{
+   if (i >= heap->size)
+     return NULL;
+
+   /*
+    * Make sure the data is sorted so we return the correct value.
+    */
+   if (!heap->sorted)
+     ecore_sheap_sort(heap);
+
+   return heap->data[i];
+}
+
+/*
+ * Regain the heap properties starting at position i
+ * @param  heap The heap to regain heap properties
+ * @param  i    The position to start heapifying
+ */
+static void
+_ecore_sheap_heapify(Ecore_Sheap *heap, int i)
+{
+   int extreme;
+   int left = LEFT(i);
+   int right = RIGHT(i);
+
+   if (heap->order == ECORE_SORT_MIN)
+     {
+       if (left <= heap->size && heap->compare(heap->data[left - 1],
+                                               heap->data[i - 1]) < 0)
+         extreme = left;
+       else
+         extreme = i;
+
+       if (right <= heap->size && heap->compare(heap->data[right - 1],
+                                                heap->data[extreme - 1]) < 0)
+         extreme = right;
+     }
+   else
+     {
+       if (left <= heap->size && heap->compare(heap->data[left - 1],
+                                               heap->data[i - 1]) > 0)
+         extreme = left;
+       else
+         extreme = i;
+
+       if (right <= heap->size && heap->compare(heap->data[right - 1],
+                                                heap->data[extreme - 1]) > 0)
+         extreme = right;
+     }
+
+   /*
+    * If the data needs to be swapped down the heap, recurse on
+    * heapifying it's new placement.
+    */
+   if (extreme != i)
+     {
+       void *temp;
+
+       temp = heap->data[extreme - 1];
+       heap->data[extreme - 1] = heap->data[i - 1];
+       heap->data[i - 1] = temp;
+
+       _ecore_sheap_heapify(heap, extreme);
+     }
+}
+
+static void
+_ecore_sheap_update_data(Ecore_Sheap *heap)
+{
+   int i, old_size;
+   void **data;
+
+   /*
+    * Track the old values from the heap
+    */
+   old_size = heap->size;
+   data = heap->data;
+
+   heap->size = 0;
+   heap->data = malloc(heap->space * sizeof(void *));
+
+   for (i = 0; i < old_size; i++)
+     ecore_sheap_insert(heap, data[i]);
+
+   FREE(data);
+}
+
+int
+ecore_direct_compare(const void *key1, const void *key2)
+{
+   unsigned long k1, k2;
+
+   k1 = (unsigned long) key1;
+   k2 = (unsigned long) key2;
+
+   if (k1 > k2)
+     return 1;
+
+   if (k1 < k2)
+     return -1;
+
+   return 0;
+}
diff --git a/src/tests/ecore_strings.c b/src/tests/ecore_strings.c
new file mode 100644 (file)
index 0000000..7395e00
--- /dev/null
@@ -0,0 +1,157 @@
+#include <stdlib.h>
+#include <string.h>
+
+#include "Ecore_Data.h"
+
+static void ecore_string_free_cb(void *data);
+
+static Ecore_Hash *ecore_strings = NULL;
+static int ecore_string_init_count = 0;
+
+/**
+ * @defgroup Ecore_String_Group String Instance Functions
+ *
+ * These functions allow you to store one copy of a string, and use it
+ * throughout your program.
+ *
+ * This is a method to reduce the number of duplicated strings kept in
+ * memory. It's pretty common for the same strings to be dynamically
+ * allocated repeatedly between applications and libraries, especially in
+ * circumstances where you could have multiple copies of a structure that
+ * allocates the string. So rather than duplicating and freeing these
+ * strings, you request a read-only pointer to an existing string and
+ * only incur the overhead of a hash lookup.
+ *
+ * It sounds like micro-optimizing, but profiling has shown this can have
+ * a significant impact as you scale the number of copies up. It improves
+ * string creation/destruction speed, reduces memory use and decreases
+ * memory fragmentation, so a win all-around.
+ */
+
+/**
+ * Initialize the ecore string internal structure.
+ * @return  Zero on failure, non-zero on successful initialization.
+ */
+EAPI int
+ecore_string_init()
+{
+   /*
+    * No strings have been loaded at this point, so create the hash
+    * table for storing string info for later.
+    */
+   if (!ecore_string_init_count)
+     {
+       ecore_strings = ecore_hash_new(ecore_str_hash, ecore_str_compare);
+       if (!ecore_strings)
+         return 0;
+       ecore_hash_free_value_cb_set(ecore_strings, ecore_string_free_cb);
+     }
+   ecore_string_init_count++;
+
+   return 1;
+}
+
+/**
+ * Retrieves an instance of a string for use in an ecore program.
+ * @param   string The string to retrieve an instance of.
+ * @return  A pointer to an instance of the string on success.
+ *          @c NULL on failure.
+ * @ingroup Ecore_String_Group
+ */
+EAPI const char *
+ecore_string_instance(const char *string)
+{
+   Ecore_String *str;
+
+   CHECK_PARAM_POINTER_RETURN("string", string, NULL);
+
+   /*
+    * Check for a previous instance of the string, if not found, create
+    * it.
+    */
+   str = ecore_hash_get(ecore_strings, string);
+   if (!str)
+     {
+       int length;
+
+       /*
+        * Allocate and initialize a new string reference.
+        */
+       length = strlen(string) + 1;
+
+       str = (Ecore_String *)malloc(sizeof(Ecore_String) + length * sizeof(char));
+
+       str->string = (char*)(str + 1);
+       str->references = 0;
+
+       memcpy(str->string, string, length);
+
+       ecore_hash_set(ecore_strings, str->string, str);
+     }
+
+   str->references++;
+
+   return str->string;
+}
+
+/**
+ * Notes that the given string has lost an instance.
+ *
+ * It will free the string if no other instances are left.
+ *
+ * @param   string The given string.
+ * @ingroup Ecore_String_Group
+ */
+EAPI void
+ecore_string_release(const char *string)
+{
+   Ecore_String *str;
+
+   CHECK_PARAM_POINTER("string", string);
+
+   str = ecore_hash_get(ecore_strings, (char *)string);
+   if (!str)
+     return;
+
+   str->references--;
+   if (str->references < 1)
+     {
+       ecore_hash_remove(ecore_strings, (char *)string);
+       FREE(str);
+     }
+}
+
+EAPI void
+ecore_string_hash_dump_graph(void)
+{
+       ecore_hash_dump_graph(ecore_strings);
+}
+
+EAPI void
+ecore_string_hash_dump_stats(void)
+{
+       ecore_hash_dump_stats(ecore_strings);
+}
+
+/**
+ * Shutdown the ecore string internal structures
+ */
+EAPI void
+ecore_string_shutdown()
+{
+   --ecore_string_init_count;
+   if (!ecore_string_init_count)
+     {
+       ecore_hash_destroy(ecore_strings);
+       ecore_strings = NULL;
+     }
+}
+
+static void
+ecore_string_free_cb(void *data)
+{
+   Ecore_String *str;
+
+   str = data;
+   FREE(str);
+}
index b2ebabf..87ee52a 100644 (file)
 # include <Evas.h>
 #endif
 
-#ifdef EINA_BENCH_HAVE_ECORE
-# include <Ecore.h>
-# include <Ecore_Data.h>
-#endif
+# include "Ecore_Data.h"
 
 #include "eina_bench.h"
 #include "eina_array.h"
@@ -633,8 +630,6 @@ eina_bench_evas_list_4evas_render(int request)
 #endif
 #endif
 
-#ifdef EINA_BENCH_HAVE_ECORE
-#if 0
 static void
 _eina_ecore_for_each_remove(void *value, void *user_data)
 {
@@ -661,7 +656,6 @@ eina_bench_ecore_list_4evas_render(int request)
    int i;
    int j;
 
-   ecore_init();
    list = ecore_list_new();
    ecore_list_free_cb_set(list, free);
 
@@ -693,11 +687,7 @@ eina_bench_ecore_list_4evas_render(int request)
      }
 
    ecore_list_destroy(list);
-
-   ecore_shutdown();
 }
-#endif
-#endif
 
 void eina_bench_array(Eina_Benchmark *bench)
 {
@@ -716,10 +706,6 @@ void eina_bench_array(Eina_Benchmark *bench)
    eina_benchmark_register(bench, "evas", EINA_BENCHMARK(eina_bench_evas_list_4evas_render), 200, 4000, 100);
 #endif
 #endif
-#ifdef EINA_BENCH_HAVE_ECORE
-#if 0
-   eina_benchmark_register(bench, "ecore", EINA_BENCHMARK(eina_bench_ecore_list_4evas_render), 200, 4000, 100);
-#endif
-#endif
+   eina_benchmark_register(bench, "ecore", EINA_BENCHMARK(eina_bench_ecore_list_4evas_render), 200, 1000, 100);
 }
 
index 268bf9a..d90abf7 100644 (file)
@@ -33,9 +33,7 @@
 # include <Evas.h>
 #endif
 
-#ifdef EINA_BENCH_HAVE_ECORE
 # include <Ecore_Data.h>
-#endif
 
 #include "eina_hash.h"
 #include "eina_array.h"
@@ -332,7 +330,6 @@ eina_bench_lookup_evas(int request)
 #endif
 #endif
 
-#ifdef EINA_BENCH_HAVE_ECORE
 typedef struct _Eina_Bench_Ecore Eina_Bench_Ecore;
 struct _Eina_Bench_Ecore
 {
@@ -379,7 +376,6 @@ eina_bench_lookup_ecore(int request)
 
    ecore_hash_destroy(hash);
 }
-#endif
 
 void eina_bench_hash(Eina_Benchmark *bench)
 {
@@ -395,7 +391,5 @@ void eina_bench_hash(Eina_Benchmark *bench)
    eina_benchmark_register(bench, "evas-lookup", EINA_BENCHMARK(eina_bench_lookup_evas), 10, 3000, 10);
 #endif
 #endif
-#ifdef EINA_BENCH_HAVE_ECORE
    eina_benchmark_register(bench, "ecore-lookup", EINA_BENCHMARK(eina_bench_lookup_ecore), 10, 3000, 10);
-#endif
 }
index bc6bc18..65caf2e 100644 (file)
 # include <Evas.h>
 #endif
 
-#ifdef EINA_BENCH_HAVE_ECORE
-# include <Ecore.h>
-# include <Ecore_Data.h>
-#endif
+# include "Ecore_Data.h"
 
 #include "eina_bench.h"
 #include "Eina.h"
@@ -137,14 +134,12 @@ eina_bench_sort_glist(int request)
 }
 #endif
 
-#ifdef EINA_BENCH_HAVE_ECORE
 static void
 eina_bench_sort_ecore_default(int request)
 {
    Ecore_List *list = NULL;
    int i;
 
-   ecore_init();
    list = ecore_list_new();
    ecore_list_free_cb_set(list, free);
 
@@ -160,8 +155,6 @@ eina_bench_sort_ecore_default(int request)
    ecore_list_sort(list, ECORE_COMPARE_CB(_eina_cmp_str), 0);
 
    ecore_list_destroy(list);
-
-   ecore_shutdown();
 }
 
 static void
@@ -170,7 +163,6 @@ eina_bench_sort_ecore_merge(int request)
    Ecore_List *list = NULL;
    int i;
 
-   ecore_init();
    list = ecore_list_new();
    ecore_list_free_cb_set(list, free);
 
@@ -186,8 +178,6 @@ eina_bench_sort_ecore_merge(int request)
    ecore_list_mergesort(list, ECORE_COMPARE_CB(_eina_cmp_str), 0);
 
    ecore_list_destroy(list);
-
-   ecore_shutdown();
 }
 
 static void
@@ -196,7 +186,6 @@ eina_bench_sort_ecore_heap(int request)
    Ecore_List *list = NULL;
    int i;
 
-   ecore_init();
    list = ecore_list_new();
    ecore_list_free_cb_set(list, free);
 
@@ -212,10 +201,7 @@ eina_bench_sort_ecore_heap(int request)
    ecore_list_heapsort(list, ECORE_COMPARE_CB(_eina_cmp_str), 0);
 
    ecore_list_destroy(list);
-
-   ecore_shutdown();
 }
-#endif
 
 void eina_bench_sort(Eina_Benchmark *bench)
 {
@@ -223,11 +209,9 @@ void eina_bench_sort(Eina_Benchmark *bench)
 #ifdef EINA_BENCH_HAVE_GLIB
    eina_benchmark_register(bench, "glist", EINA_BENCHMARK(eina_bench_sort_glist), 10, 10000, 100);
 #endif
-#ifdef EINA_BENCH_HAVE_ECORE
    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);
-#endif
 #ifdef EINA_BENCH_HAVE_EVAS
 #if 0
    eina_benchmark_register(bench, "evas", EINA_BENCHMARK(eina_bench_sort_evas), 10, 10000, 100);
index 092d807..acea043 100644 (file)
@@ -32,9 +32,7 @@
 # include <Evas.h>
 #endif
 
-#ifdef EINA_BENCH_HAVE_ECORE
-# include <Ecore_Data.h>
-#endif
+# include "Ecore_Data.h"
 
 #include "eina_stringshare.h"
 #include "eina_bench.h"
@@ -141,7 +139,6 @@ eina_bench_evas_job(int request)
 #endif
 #endif
 
-#ifdef EINA_BENCH_HAVE_ECORE
 static void
 eina_bench_ecore_job(int request)
 {
@@ -172,7 +169,6 @@ eina_bench_ecore_job(int request)
 
    ecore_string_shutdown();
 }
-#endif
 
 void eina_bench_stringshare(Eina_Benchmark *bench)
 {
@@ -185,7 +181,5 @@ void eina_bench_stringshare(Eina_Benchmark *bench)
    eina_benchmark_register(bench, "stringshare (evas)", EINA_BENCHMARK(eina_bench_evas_job), 100, 20100, 500);
 #endif
 #endif
-#ifdef EINA_BENCH_HAVE_ECORE
    eina_benchmark_register(bench, "stringshare (ecore)", EINA_BENCHMARK(eina_bench_ecore_job), 100, 20100, 500);
-#endif
 }