Merge Ewd code into Ecore.
The new functions (Ecore_Data.h) have not been tested yet, be warned! :) SVN revision: 9384
This commit is contained in:
parent
002beaf9a6
commit
1034f13443
|
@ -6,12 +6,32 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <dlfcn.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <dirent.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include <Ecore_Data.h>
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
#ifndef PATH_MAX
|
||||
#define PATH_MAX 4096
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Convenience macros */
|
||||
/* FIXME: [deprecated] Convenience macros */
|
||||
#define ECORE_MIN(x, y) (((x) > (y)) ? (y) : (x))
|
||||
#define ECORE_MAX(x, y) (((x) > (y)) ? (x) : (y))
|
||||
|
||||
|
|
|
@ -0,0 +1,546 @@
|
|||
#ifndef _ECORE_DATA_H
|
||||
#define _ECORE_DATA_H
|
||||
|
||||
#define PRIME_TABLE_MAX 21
|
||||
#define PRIME_MIN 17
|
||||
#define PRIME_MAX 16777213
|
||||
|
||||
extern const unsigned int ecore_prime_table[];
|
||||
|
||||
typedef void (*Ecore_For_Each) (void *value);
|
||||
#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) (void *key);
|
||||
#define ECORE_HASH_CB(function) ((Ecore_Hash_Cb)function)
|
||||
|
||||
typedef int (*Ecore_Compare_Cb) (void *data1, void *data2);
|
||||
#define ECORE_COMPARE_CB(function) ((Ecore_Compare_Cb)function)
|
||||
|
||||
int ecore_direct_compare(void *key1, void *key2);
|
||||
int ecore_str_compare(void *key1, void *key2);
|
||||
|
||||
unsigned int ecore_direct_hash(void *key);
|
||||
unsigned int ecore_str_hash(void *key);
|
||||
|
||||
|
||||
#ifdef HAVE_PTHREADS /* pthreads are installed */
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#define ECORE_DECLARE_LOCKS \
|
||||
int readers; \
|
||||
pthread_mutex_t readers_mutex; \
|
||||
pthread_mutex_t writers_mutex; \
|
||||
pthread_cond_t readers_cond;
|
||||
|
||||
#define ECORE_INIT_LOCKS(structure) \
|
||||
if (structure) { \
|
||||
structure->readers = 0; \
|
||||
pthread_mutex_init(&structure->readers_mutex, NULL); \
|
||||
pthread_mutex_init(&structure->writers_mutex, NULL); \
|
||||
pthread_cond_init(&structure->readers_cond, NULL); \
|
||||
}
|
||||
|
||||
#define ECORE_DESTROY_LOCKS(structure) \
|
||||
if (structure) { \
|
||||
pthread_mutex_destroy(&structure->readers_mutex); \
|
||||
pthread_mutex_destroy(&structure->writers_mutex); \
|
||||
pthread_cond_destroy(&structure->readers_cond); \
|
||||
}
|
||||
|
||||
#define ECORE_READ_LOCK(structure) \
|
||||
if (structure) { \
|
||||
pthread_mutex_lock(&structure->readers_mutex); \
|
||||
structure->readers++; \
|
||||
pthread_mutex_unlock(&structure->readers_mutex); \
|
||||
}
|
||||
|
||||
#define ECORE_READ_UNLOCK(structure) \
|
||||
if (structure) { \
|
||||
pthread_mutex_lock(&structure->readers_mutex); \
|
||||
if (--structure->readers == 0) \
|
||||
pthread_cond_broadcast(&structure->readers_cond); \
|
||||
pthread_mutex_unlock(&structure->readers_mutex); \
|
||||
}
|
||||
|
||||
#define ECORE_WRITE_LOCK(structure) \
|
||||
if (structure) { \
|
||||
pthread_mutex_lock(&structure->readers_mutex); \
|
||||
pthread_mutex_lock(&structure->writers_mutex); \
|
||||
while (structure->readers > 0) \
|
||||
pthread_cond_wait(&structure->readers_cond, \
|
||||
&structure->readers_mutex); \
|
||||
pthread_mutex_unlock(&structure->readers_mutex); \
|
||||
}
|
||||
|
||||
#define ECORE_WRITE_UNLOCK(structure) \
|
||||
if (structure) \
|
||||
pthread_mutex_unlock(&structure->writers_mutex); \
|
||||
|
||||
#define ECORE_THREAD_CREATE(function, arg) \
|
||||
if (function) { \
|
||||
pthread_t thread; \
|
||||
pthread_create(&thread, NULL, function, arg); \
|
||||
pthread_detach(thread); \
|
||||
}
|
||||
|
||||
#define ECORE_NO_THREADS(function, arg)
|
||||
|
||||
#else /* No pthreads available */
|
||||
|
||||
#define ECORE_DECLARE_LOCKS
|
||||
#define ECORE_INIT_LOCKS(structure)
|
||||
#define ECORE_READ_LOCK(structure)
|
||||
#define ECORE_READ_UNLOCK(structure)
|
||||
#define ECORE_WRITE_LOCK(structure)
|
||||
#define ECORE_WRITE_UNLOCK(structure)
|
||||
#define ECORE_THREAD_CREATE(function, args)
|
||||
#define ECORE_DESTROY_LOCKS(structure)
|
||||
|
||||
#define ECORE_NO_THREADS(function, arg) if (function) function(arg);
|
||||
|
||||
#endif /* HAVE_PTHREADS */
|
||||
|
||||
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)
|
||||
|
||||
struct _ecore_list_node {
|
||||
void *data;
|
||||
struct _ecore_list_node *next;
|
||||
|
||||
ECORE_DECLARE_LOCKS;
|
||||
};
|
||||
|
||||
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 */
|
||||
ECORE_DECLARE_LOCKS;
|
||||
};
|
||||
|
||||
|
||||
/* Creating and initializing new list structures */
|
||||
Ecore_List *ecore_list_new();
|
||||
int ecore_list_init(Ecore_List *list);
|
||||
|
||||
/* Adding items to the list */
|
||||
inline int ecore_list_append(Ecore_List * list, void *_data);
|
||||
inline int ecore_list_prepend(Ecore_List * list, void *_data);
|
||||
inline int ecore_list_insert(Ecore_List * list, void *_data);
|
||||
|
||||
/* Removing items from the list */
|
||||
inline int ecore_list_remove_destroy(Ecore_List *list);
|
||||
inline void *ecore_list_remove(Ecore_List * list);
|
||||
inline void *ecore_list_remove_first(Ecore_List * list);
|
||||
inline void *ecore_list_remove_last(Ecore_List * list);
|
||||
|
||||
/* Retrieve the current position in the list */
|
||||
inline void *ecore_list_current(Ecore_List * list);
|
||||
int ecore_list_index(Ecore_List * list);
|
||||
int ecore_list_nodes(Ecore_List * list);
|
||||
|
||||
/* Traversing the list */
|
||||
int ecore_list_for_each(Ecore_List *list, Ecore_For_Each function);
|
||||
inline void *ecore_list_goto_first(Ecore_List * list);
|
||||
inline void *ecore_list_goto_last(Ecore_List * list);
|
||||
inline void *ecore_list_goto_index(Ecore_List * list, int index);
|
||||
inline void *ecore_list_goto(Ecore_List * list, void *_data);
|
||||
|
||||
/* Traversing the list and returning data */
|
||||
inline void *ecore_list_next(Ecore_List * list);
|
||||
|
||||
/* Check to see if there is any data in the list */
|
||||
int ecore_list_is_empty(Ecore_List * list);
|
||||
|
||||
/* Remove every node in the list without freeing the list itself */
|
||||
int ecore_list_clear(Ecore_List * list);
|
||||
/* Free the list and it's contents */
|
||||
void ecore_list_destroy(Ecore_List *list);
|
||||
|
||||
/* Creating and initializing list nodes */
|
||||
Ecore_List_Node *ecore_list_node_new();
|
||||
int ecore_list_node_init(Ecore_List_Node *newNode);
|
||||
|
||||
/* Destroying nodes */
|
||||
int ecore_list_node_destroy(Ecore_List_Node * _e_node, Ecore_Free_Cb free_func);
|
||||
|
||||
int ecore_list_set_free_cb(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 */
|
||||
Ecore_DList *ecore_dlist_new();
|
||||
int ecore_dlist_init(Ecore_DList *list);
|
||||
void ecore_dlist_destroy(Ecore_DList *list);
|
||||
|
||||
/* Adding items to the list */
|
||||
int ecore_dlist_append(Ecore_DList * _e_dlist, void *_data);
|
||||
int ecore_dlist_prepend(Ecore_DList * _e_dlist, void *_data);
|
||||
int ecore_dlist_insert(Ecore_DList * _e_dlist, void *_data);
|
||||
|
||||
/* Info about list's state */
|
||||
void *ecore_dlist_current(Ecore_DList *list);
|
||||
int ecore_dlist_index(Ecore_DList *list);
|
||||
#define ecore_dlist_nodes(list) ecore_list_nodes(ECORE_LIST(list))
|
||||
|
||||
/* Removing items from the list */
|
||||
void *ecore_dlist_remove(Ecore_DList * _e_dlist);
|
||||
void *ecore_dlist_remove_first(Ecore_DList * _e_dlist);
|
||||
void *ecore_dlist_remove_last(Ecore_DList * _e_dlist);
|
||||
|
||||
/* Traversing the list */
|
||||
#define ecore_dlist_for_each(list, function) \
|
||||
ecore_list_for_each(ECORE_LIST(list), function)
|
||||
inline void *ecore_dlist_goto_first(Ecore_DList * _e_dlist);
|
||||
inline void *ecore_dlist_goto_last(Ecore_DList * _e_dlist);
|
||||
inline void *ecore_dlist_goto_index(Ecore_DList * _e_dlist, int index);
|
||||
inline void *ecore_dlist_goto(Ecore_DList * _e_dlist, void *_data);
|
||||
|
||||
/* Traversing the list and returning data */
|
||||
inline void *ecore_dlist_next(Ecore_DList * list);
|
||||
inline void *ecore_dlist_previous(Ecore_DList * list);
|
||||
|
||||
/* Check to see if there is any data in the list */
|
||||
int ecore_dlist_is_empty(Ecore_DList * _e_dlist);
|
||||
|
||||
/* Remove every node in the list without free'ing it */
|
||||
int ecore_dlist_clear(Ecore_DList * _e_dlist);
|
||||
|
||||
/* Creating and initializing list nodes */
|
||||
Ecore_DList_Node *ecore_dlist_node_new();
|
||||
|
||||
/* Destroying nodes */
|
||||
int ecore_dlist_node_destroy(Ecore_DList_Node * node, Ecore_Free_Cb free_func);
|
||||
|
||||
int ecore_dlist_set_free_cb(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 {
|
||||
void *key; /* The key for the data node */
|
||||
void *value; /* The value associated with this node */
|
||||
|
||||
ECORE_DECLARE_LOCKS
|
||||
};
|
||||
|
||||
typedef struct _ecore_hash Ecore_Hash;
|
||||
#define ECORE_HASH(hash) ((Ecore_Hash *)hash)
|
||||
|
||||
struct _ecore_hash {
|
||||
Ecore_List **buckets;
|
||||
int size; /* An index into the table of primes to
|
||||
determine size */
|
||||
int nodes; /* The number of nodes currently in the hash */
|
||||
|
||||
Ecore_Compare_Cb compare; /* The function used to compare node values */
|
||||
Ecore_Hash_Cb hash_func; /* The function used to compare node values */
|
||||
|
||||
Ecore_Free_Cb free_key; /* The callback function to free key */
|
||||
Ecore_Free_Cb free_value; /* The callback function to determine hash */
|
||||
|
||||
ECORE_DECLARE_LOCKS
|
||||
};
|
||||
|
||||
/* Create and initialize a hash */
|
||||
Ecore_Hash *ecore_hash_new(Ecore_Hash_Cb hash_func, Ecore_Compare_Cb compare);
|
||||
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 */
|
||||
int ecore_hash_set_free_key(Ecore_Hash *hash, Ecore_Free_Cb function);
|
||||
int ecore_hash_set_free_value(Ecore_Hash *hash, Ecore_Free_Cb function);
|
||||
void ecore_hash_destroy(Ecore_Hash *hash);
|
||||
int ecore_hash_for_each_node(Ecore_Hash *hash, Ecore_For_Each for_each_func);
|
||||
|
||||
/* Retrieve and store data into the hash */
|
||||
void *ecore_hash_get(Ecore_Hash *hash, void *key);
|
||||
int ecore_hash_set(Ecore_Hash *hash, void *key, void *value);
|
||||
void *ecore_hash_remove(Ecore_Hash *hash, void *key);
|
||||
void ecore_hash_dump_graph(Ecore_Hash *hash);
|
||||
|
||||
|
||||
inline void ecore_print_warning(char *function, char *sparam);
|
||||
|
||||
/* Wrappers around free() that helps debug free() bugs such as freeing NULL
|
||||
* or accessing a pointer that has already been freed */
|
||||
#ifndef IF_FREE
|
||||
#define IF_FREE(ptr) if (ptr) free(ptr); ptr = NULL;
|
||||
#endif
|
||||
|
||||
#ifndef FREE
|
||||
#define FREE(ptr) free(ptr); ptr = NULL;
|
||||
#endif
|
||||
|
||||
/* Debugging printf, basically a wrapper to fprintf that checks the level
|
||||
* of the message and checks that it is to be printed at the current debugging
|
||||
* level */
|
||||
#ifndef DPRINTF
|
||||
#define DPRINTF(debug, format, args...) \
|
||||
if (debug >= DEBUG_LEVEL) \
|
||||
fprintf(stderr, format, args);
|
||||
#endif
|
||||
|
||||
/* convenience macros for checking pointer parameters for non-NULL */
|
||||
#ifndef CHECK_PARAM_POINTER_RETURN
|
||||
#define CHECK_PARAM_POINTER_RETURN(sparam, param, ret) \
|
||||
if (!(param)) \
|
||||
{ \
|
||||
ecore_print_warning(__FUNCTION__, sparam); \
|
||||
return ret; \
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef CHECK_PARAM_POINTER
|
||||
#define CHECK_PARAM_POINTER(sparam, param) \
|
||||
if (!(param)) \
|
||||
{ \
|
||||
ecore_print_warning(__FUNCTION__, sparam); \
|
||||
return; \
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Use the larger of a and b */
|
||||
#ifndef MAX
|
||||
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
/* Use the smaller of a and b */
|
||||
#ifndef MIN
|
||||
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
|
||||
typedef struct _ecore_path_group Ecore_Path_Group;
|
||||
struct _ecore_path_group
|
||||
{
|
||||
int id;
|
||||
char *name;
|
||||
Ecore_List *paths;
|
||||
};
|
||||
|
||||
/*
|
||||
* Create a new path group
|
||||
*/
|
||||
int ecore_path_group_new(char *group_name);
|
||||
|
||||
/*
|
||||
* Destroy a previous path group
|
||||
*/
|
||||
void ecore_path_group_del(int group_id);
|
||||
|
||||
/*
|
||||
* Add a directory to be searched for files
|
||||
*/
|
||||
void ecore_path_group_add(int group_id, char *path);
|
||||
|
||||
/*
|
||||
* Remove a directory to be searched for files
|
||||
*/
|
||||
void ecore_path_group_remove(int group_id, char *path);
|
||||
|
||||
/*
|
||||
* Find the absolute path if it exists in the group of paths
|
||||
*/
|
||||
char * ecore_path_group_find(int group_id, char *name);
|
||||
|
||||
/*
|
||||
* Get a list of all the available files in a path set
|
||||
*/
|
||||
Ecore_List * ecore_path_group_available(int group_id);
|
||||
|
||||
|
||||
typedef struct _ecore_plugin Ecore_Plugin;
|
||||
struct _ecore_plugin
|
||||
{
|
||||
int group;
|
||||
char *name;
|
||||
void *handle;
|
||||
};
|
||||
|
||||
/*
|
||||
* Load the specified plugin
|
||||
*/
|
||||
Ecore_Plugin *ecore_plugin_load(int group_id, char *plugin);
|
||||
|
||||
/*
|
||||
* Unload the specified plugin
|
||||
*/
|
||||
void ecore_plugin_unload(Ecore_Plugin * plugin);
|
||||
|
||||
/*
|
||||
* Lookup the specified symbol for the plugin
|
||||
*/
|
||||
void *ecore_plugin_call(Ecore_Plugin * plugin, char *symbol_name);
|
||||
|
||||
Ecore_List *ecore_plugin_get_available(int group_id);
|
||||
|
||||
|
||||
#define ECORE_SHEAP_MIN 0
|
||||
#define ECORE_SHEAP_MAX 1
|
||||
|
||||
#define HEAP_INCREMENT 4096
|
||||
|
||||
#define PARENT(i) (i / 2)
|
||||
#define LEFT(i) (2 * i)
|
||||
#define RIGHT(i) (2 * i + 1)
|
||||
|
||||
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;
|
||||
|
||||
Ecore_Compare_Cb compare;
|
||||
};
|
||||
|
||||
Ecore_Sheap *ecore_sheap_new(Ecore_Compare_Cb compare, int size);
|
||||
void ecore_sheap_destroy(Ecore_Sheap *heap);
|
||||
int ecore_sheap_init(Ecore_Sheap *heap, Ecore_Compare_Cb compare, int size);
|
||||
int ecore_sheap_insert(Ecore_Sheap *heap, void *data);
|
||||
void *ecore_sheap_extract(Ecore_Sheap *heap);
|
||||
void *ecore_sheap_extreme(Ecore_Sheap *heap);
|
||||
int ecore_sheap_change(Ecore_Sheap *heap, void *item, void *newval);
|
||||
void ecore_sheap_destroy(Ecore_Sheap *heap);
|
||||
void ecore_sheap_sort(Ecore_Sheap *heap);
|
||||
|
||||
inline void *ecore_sheap_item(Ecore_Sheap *heap, int i);
|
||||
|
||||
|
||||
typedef struct _ecore_string Ecore_String;
|
||||
struct _ecore_string {
|
||||
char *string;
|
||||
int references;
|
||||
};
|
||||
|
||||
char *ecore_string_instance(char *string);
|
||||
void ecore_string_release(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;
|
||||
|
||||
ECORE_DECLARE_LOCKS;
|
||||
};
|
||||
|
||||
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_func;
|
||||
|
||||
ECORE_DECLARE_LOCKS;
|
||||
};
|
||||
|
||||
/* Some basic tree functions */
|
||||
/* Allocate and initialize a new tree */
|
||||
Ecore_Tree *ecore_tree_new(Ecore_Compare_Cb compare_func);
|
||||
/* Initialize a new tree */
|
||||
int ecore_tree_init(Ecore_Tree * tree, Ecore_Compare_Cb compare_func);
|
||||
|
||||
/* Free the tree */
|
||||
int ecore_tree_destroy(Ecore_Tree * tree);
|
||||
/* Check to see if the tree has any nodes in it */
|
||||
int ecore_tree_is_empty(Ecore_Tree * tree);
|
||||
|
||||
/* Retrieve the value associated with key */
|
||||
void *ecore_tree_get(Ecore_Tree * tree, void *key);
|
||||
Ecore_Tree_Node *ecore_tree_get_node(Ecore_Tree * tree, void *key);
|
||||
/* Retrieve the value of node with key greater than or equal to key */
|
||||
void *ecore_tree_get_closest_larger(Ecore_Tree * tree, void *key);
|
||||
/* Retrieve the value of node with key less than or equal to key */
|
||||
void *ecore_tree_get_closest_smaller(Ecore_Tree * tree, void *key);
|
||||
|
||||
/* Set the value associated with key to value */
|
||||
int ecore_tree_set(Ecore_Tree * tree, void *key, void *value);
|
||||
/* Remove the key from the tree */
|
||||
int ecore_tree_remove(Ecore_Tree * tree, void *key);
|
||||
|
||||
/* Add a node to the tree */
|
||||
int ecore_tree_add_node(Ecore_Tree * tree, Ecore_Tree_Node * node);
|
||||
/* Remove a node from the tree */
|
||||
int ecore_tree_remove_node(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 */
|
||||
int ecore_tree_for_each_node(Ecore_Tree * tree, Ecore_For_Each for_each_func);
|
||||
/* And here pass in the node's value */
|
||||
int ecore_tree_for_each_node_value(Ecore_Tree * tree,
|
||||
Ecore_For_Each for_each_func);
|
||||
|
||||
/* Some basic node functions */
|
||||
/* Initialize a node */
|
||||
int ecore_tree_node_init(Ecore_Tree_Node * new_node);
|
||||
/* Allocate and initialize a new node */
|
||||
Ecore_Tree_Node *ecore_tree_node_new();
|
||||
/* Free the desired node */
|
||||
int ecore_tree_node_destroy(Ecore_Tree_Node * node, Ecore_Free_Cb free_data);
|
||||
|
||||
/* Set the node's key to key */
|
||||
int ecore_tree_node_key_set(Ecore_Tree_Node * node, void *key);
|
||||
/* Retrieve the key in node */
|
||||
void *ecore_tree_node_key_get(Ecore_Tree_Node * node);
|
||||
|
||||
/* Set the node's value to value */
|
||||
int ecore_tree_node_value_set(Ecore_Tree_Node * node, void *value);
|
||||
/* Retrieve the value in node */
|
||||
void *ecore_tree_node_value_get(Ecore_Tree_Node * node);
|
||||
|
||||
/* Add a function to free the data stored in nodes */
|
||||
int ecore_tree_set_free_cb(Ecore_Tree * tree, Ecore_Free_Cb free_func);
|
||||
|
||||
#endif /* _ECORE_DATA_H */
|
|
@ -4,22 +4,30 @@ INCLUDES =
|
|||
|
||||
lib_LTLIBRARIES = libecore.la
|
||||
include_HEADERS = \
|
||||
Ecore.h
|
||||
Ecore.h \
|
||||
Ecore_Data.h
|
||||
|
||||
libecore_la_SOURCES = \
|
||||
ecore.c \
|
||||
ecore_app.c \
|
||||
ecore_events.c \
|
||||
ecore_exe.c \
|
||||
ecore_hash.c \
|
||||
ecore_idle_enterer.c \
|
||||
ecore_idle_exiter.c \
|
||||
ecore_idler.c \
|
||||
ecore_list.c \
|
||||
ecore_main.c \
|
||||
ecore_path.c \
|
||||
ecore_plugin.c \
|
||||
ecore_sheap.c \
|
||||
ecore_signal.c \
|
||||
ecore_strings.c \
|
||||
ecore_time.c \
|
||||
ecore_timer.c \
|
||||
ecore_tree.c \
|
||||
ecore_value.c \
|
||||
ecore_private.h
|
||||
|
||||
libecore_la_LIBADD =
|
||||
libecore_la_LIBADD = -lm @dlopen_libs@
|
||||
libecore_la_LDFLAGS = -version-info 1:0:0
|
||||
|
|
|
@ -353,20 +353,20 @@ _ecore_event_del(Ecore_Event *event)
|
|||
void
|
||||
_ecore_event_call(void)
|
||||
{
|
||||
Ecore_List *l;
|
||||
Ecore_Oldlist *l;
|
||||
|
||||
for (l = (Ecore_List *)event_filters; l; l = l->next)
|
||||
for (l = (Ecore_Oldlist *)event_filters; l; l = l->next)
|
||||
{
|
||||
Ecore_Event_Filter *ef;
|
||||
|
||||
ef = (Ecore_Event_Filter *)l;
|
||||
if (!ef->delete_me)
|
||||
{
|
||||
Ecore_List *ll;
|
||||
Ecore_Oldlist *ll;
|
||||
|
||||
if (ef->func_start)
|
||||
ef->loop_data = ef->func_start(ef->data);
|
||||
for (ll = (Ecore_List *)events; ll; ll = ll->next)
|
||||
for (ll = (Ecore_Oldlist *)events; ll; ll = ll->next)
|
||||
{
|
||||
Ecore_Event *e;
|
||||
|
||||
|
@ -381,7 +381,7 @@ _ecore_event_call(void)
|
|||
}
|
||||
if (event_filters_delete_me)
|
||||
{
|
||||
for (l = (Ecore_List *)event_filters; l;)
|
||||
for (l = (Ecore_Oldlist *)event_filters; l;)
|
||||
{
|
||||
Ecore_Event_Filter *ef;
|
||||
|
||||
|
@ -396,9 +396,9 @@ _ecore_event_call(void)
|
|||
}
|
||||
event_filters_delete_me = 0;
|
||||
}
|
||||
for (l = (Ecore_List *)events; l; l = l->next)
|
||||
for (l = (Ecore_Oldlist *)events; l; l = l->next)
|
||||
{
|
||||
Ecore_List *ll;
|
||||
Ecore_Oldlist *ll;
|
||||
Ecore_Event *e;
|
||||
|
||||
e = (Ecore_Event *)l;
|
||||
|
@ -409,7 +409,7 @@ _ecore_event_call(void)
|
|||
handle_count = 0;
|
||||
ecore_raw_event_type = e->type;
|
||||
ecore_raw_event_event = e->event;
|
||||
for (ll = (Ecore_List *)event_handlers; ll; ll = ll->next)
|
||||
for (ll = (Ecore_Oldlist *)event_handlers; ll; ll = ll->next)
|
||||
{
|
||||
Ecore_Event_Handler *eh;
|
||||
|
||||
|
@ -434,7 +434,7 @@ _ecore_event_call(void)
|
|||
}
|
||||
while (events) _ecore_event_del(events);
|
||||
if (!event_handlers_delete_me) return;
|
||||
for (l = (Ecore_List *)event_handlers; l;)
|
||||
for (l = (Ecore_Oldlist *)event_handlers; l;)
|
||||
{
|
||||
Ecore_Event_Handler *eh;
|
||||
|
||||
|
|
|
@ -237,9 +237,9 @@ _ecore_exe_shutdown(void)
|
|||
Ecore_Exe *
|
||||
_ecore_exe_find(pid_t pid)
|
||||
{
|
||||
Ecore_List *l;
|
||||
Ecore_Oldlist *l;
|
||||
|
||||
for (l = (Ecore_List *)exes; l; l = l->next)
|
||||
for (l = (Ecore_Oldlist *)exes; l; l = l->next)
|
||||
{
|
||||
Ecore_Exe *exe;
|
||||
|
||||
|
|
|
@ -0,0 +1,648 @@
|
|||
#include <Ecore.h>
|
||||
|
||||
#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 && hash->size < PRIME_MAX) ? \
|
||||
(hash->nodes / ecore_prime_table[hash->size]) > \
|
||||
ECORE_HASH_CHAIN_MAX : FALSE)
|
||||
#define ECORE_HASH_REDUCE(hash) ((hash && hash->size > PRIME_MIN) ? \
|
||||
(double)hash->nodes / (double)ecore_prime_table[hash->size-1] \
|
||||
< ((double)ECORE_HASH_CHAIN_MAX * 0.375) : FALSE)
|
||||
|
||||
|
||||
/* Private hash manipulation functions */
|
||||
static int _ecore_hash_add_node(Ecore_Hash *hash, Ecore_Hash_Node *node);
|
||||
static Ecore_Hash_Node * _ecore_hash_get_node(Ecore_Hash *hash, void *key);
|
||||
static int _ecore_hash_increase(Ecore_Hash *hash);
|
||||
static int _ecore_hash_decrease(Ecore_Hash *hash);
|
||||
inline int _ecore_hash_rehash(Ecore_Hash *hash, Ecore_List **old_table, int old_size);
|
||||
static int _ecore_hash_bucket_destroy(Ecore_List *list, Ecore_Free_Cb keyd,
|
||||
Ecore_Free_Cb valued);
|
||||
inline Ecore_Hash_Node * _ecore_hash_get_bucket(Ecore_Hash *hash, Ecore_List *bucket,
|
||||
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);
|
||||
|
||||
|
||||
/**
|
||||
* ecore_hash_new - create and initialize a new hash
|
||||
* @hash_func: the function for determining hash position
|
||||
* @compare: the function for comparing node keys
|
||||
*
|
||||
* Returns NULL on error, a new hash on success
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* ecore_hash_init - initialize a hash to some sane starting values
|
||||
* @hash: the hash table to initialize
|
||||
* @hash_func: the function for hashing node keys
|
||||
* @compare: the function for comparing node keys
|
||||
*
|
||||
* Returns TRUE on success, FALSE on an error.
|
||||
*/
|
||||
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_List **)malloc(ecore_prime_table[0] *
|
||||
sizeof(Ecore_List *));
|
||||
memset(hash->buckets, 0, ecore_prime_table[0] * sizeof(Ecore_List *));
|
||||
|
||||
ECORE_INIT_LOCKS(hash);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* ecore_hash_set_free_key - set the function to destroy the keys of entries
|
||||
* @hash: the hash that this will affect
|
||||
* @function: the function that will free the node keys
|
||||
*
|
||||
* Returns TRUE on success, FALSE on error
|
||||
*/
|
||||
int ecore_hash_set_free_key(Ecore_Hash *hash, Ecore_Free_Cb function)
|
||||
{
|
||||
CHECK_PARAM_POINTER_RETURN("hash", hash, FALSE);
|
||||
CHECK_PARAM_POINTER_RETURN("function", function, FALSE);
|
||||
|
||||
ECORE_WRITE_LOCK(hash);
|
||||
hash->free_key = function;
|
||||
ECORE_WRITE_UNLOCK(hash);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* ecore_hash_set_free_value - set the function to destroy the value
|
||||
* @hash: the hash that this will affect
|
||||
* @function: the function that will free the node values
|
||||
*
|
||||
* Returns TRUE on success, FALSE on error
|
||||
*/
|
||||
int ecore_hash_set_free_value(Ecore_Hash *hash, Ecore_Free_Cb function)
|
||||
{
|
||||
CHECK_PARAM_POINTER_RETURN("hash", hash, FALSE);
|
||||
CHECK_PARAM_POINTER_RETURN("function", function, FALSE);
|
||||
|
||||
ECORE_WRITE_LOCK(hash);
|
||||
hash->free_value = function;
|
||||
ECORE_WRITE_UNLOCK(hash);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* ecore_hash_set - set the key/value pair in the hash table
|
||||
* @hash: the hash table to set the the value in
|
||||
* @key: the key for this value pair
|
||||
* @value: the value corresponding with the key
|
||||
*
|
||||
* Returns TRUE if successful, FALSE if not
|
||||
*/
|
||||
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);
|
||||
|
||||
ECORE_WRITE_LOCK(hash);
|
||||
node = _ecore_hash_get_node(hash, key);
|
||||
if (node)
|
||||
node->value = value;
|
||||
else {
|
||||
node = _ecore_hash_node_new(key, value);
|
||||
if (node)
|
||||
ret = _ecore_hash_add_node(hash, node);
|
||||
}
|
||||
ECORE_WRITE_UNLOCK(hash);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* ecore_hash_destroy - free the hash table and the data contained inside it
|
||||
* @hash: the hash table to destroy
|
||||
*
|
||||
* Returns TRUE on success, FALSE on error
|
||||
*/
|
||||
void ecore_hash_destroy(Ecore_Hash *hash)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
CHECK_PARAM_POINTER("hash", hash);
|
||||
|
||||
ECORE_WRITE_LOCK(hash);
|
||||
|
||||
while (i < ecore_prime_table[hash->size]) {
|
||||
if (hash->buckets[i])
|
||||
_ecore_hash_bucket_destroy(hash->buckets[i],
|
||||
hash->free_key, hash->free_value);
|
||||
i++;
|
||||
}
|
||||
|
||||
FREE(hash->buckets);
|
||||
|
||||
ECORE_WRITE_UNLOCK(hash);
|
||||
ECORE_DESTROY_LOCKS(hash);
|
||||
|
||||
FREE(hash);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* ecore_hash_for_each - iterate over the entries in the hash table
|
||||
*/
|
||||
int ecore_hash_for_each_node(Ecore_Hash *hash, Ecore_For_Each for_each_func)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
CHECK_PARAM_POINTER_RETURN("hash", hash, FALSE);
|
||||
CHECK_PARAM_POINTER_RETURN("for_each_func", for_each_func, FALSE);
|
||||
|
||||
ECORE_READ_LOCK(hash);
|
||||
|
||||
while (i < ecore_prime_table[hash->size]) {
|
||||
if (hash->buckets[i]) {
|
||||
Ecore_Hash_Node *node;
|
||||
|
||||
ecore_list_goto_first(hash->buckets[i]);
|
||||
while ((node = ecore_list_next(hash->buckets[i]))) {
|
||||
for_each_func(node);
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
ECORE_READ_UNLOCK(hash);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* ecore_hash_dump_graph - print the distribution of the hash table for graphing
|
||||
* @hash: the hash table to print
|
||||
*
|
||||
* Returns no value.
|
||||
*/
|
||||
void
|
||||
ecore_hash_dump_graph(Ecore_Hash *hash)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ecore_prime_table[hash->size]; i++)
|
||||
if (hash->buckets[i])
|
||||
printf("%d\t%u\n", i, ecore_list_nodes(hash->buckets[i]));
|
||||
else
|
||||
printf("%d\t0\n", i);
|
||||
}
|
||||
|
||||
static int
|
||||
_ecore_hash_bucket_destroy(Ecore_List *list, Ecore_Free_Cb keyd, Ecore_Free_Cb valued)
|
||||
{
|
||||
Ecore_Hash_Node *node;
|
||||
|
||||
CHECK_PARAM_POINTER_RETURN("list", list, FALSE);
|
||||
|
||||
while ((node = ecore_list_remove_first(list)) != NULL)
|
||||
_ecore_hash_node_destroy(node, keyd, valued);
|
||||
|
||||
ecore_list_destroy(list);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Description: Add the node to the hash table
|
||||
* Parameters: 1. hash - the hash table to add the key
|
||||
* 2. node - the node to add to the hash table
|
||||
* Returns: FALSE on error, TRUE on success
|
||||
*/
|
||||
static int
|
||||
_ecore_hash_add_node(Ecore_Hash *hash, Ecore_Hash_Node *node)
|
||||
{
|
||||
unsigned int 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 int)node->key %
|
||||
ecore_prime_table[hash->size];
|
||||
else
|
||||
hash_val = ECORE_COMPUTE_HASH(hash, node->key);
|
||||
|
||||
/* Create the list if it's not already present */
|
||||
if (!hash->buckets[hash_val])
|
||||
hash->buckets[hash_val] = ecore_list_new();
|
||||
|
||||
/* Append the node to the list at the index position */
|
||||
if (!ecore_list_prepend(hash->buckets[hash_val], node))
|
||||
return FALSE;
|
||||
hash->nodes++;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* ecore_hash_get - retrieve the value associated with key
|
||||
* @hash: the hash table to search for the key
|
||||
* @key: the key to search for in the hash table
|
||||
*
|
||||
* Returns NULL on error, value corresponding to key on success
|
||||
*/
|
||||
void *ecore_hash_get(Ecore_Hash *hash, void *key)
|
||||
{
|
||||
void *data;
|
||||
Ecore_Hash_Node *node;
|
||||
|
||||
CHECK_PARAM_POINTER_RETURN("hash", hash, FALSE);
|
||||
|
||||
node = _ecore_hash_get_node(hash, key);
|
||||
if (!node)
|
||||
return NULL;
|
||||
|
||||
ECORE_READ_LOCK(node);
|
||||
data = node->value;
|
||||
ECORE_READ_UNLOCK(node);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ecore_hash_remove - remove the value associated with key
|
||||
* @hash: the hash table to remove the key from
|
||||
* @key: the key to search for in the hash table
|
||||
*
|
||||
* Returns NULL on error, value corresponding to key on success
|
||||
*/
|
||||
void *ecore_hash_remove(Ecore_Hash *hash, void *key)
|
||||
{
|
||||
Ecore_Hash_Node *node = NULL;
|
||||
Ecore_List *list;
|
||||
unsigned int hash_val;
|
||||
void *ret = NULL;
|
||||
|
||||
CHECK_PARAM_POINTER_RETURN("hash", hash, NULL);
|
||||
|
||||
ECORE_WRITE_LOCK(hash);
|
||||
|
||||
/* Compute the position in the table */
|
||||
if (!hash->hash_func)
|
||||
hash_val = (unsigned int)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];
|
||||
ecore_list_goto_first(list);
|
||||
|
||||
/*
|
||||
* Traverse the list to find the specified key
|
||||
*/
|
||||
if (hash->compare) {
|
||||
while ((node = ecore_list_current(list)) &&
|
||||
hash->compare(node->key, key) != 0)
|
||||
ecore_list_next(list);
|
||||
}
|
||||
else {
|
||||
while ((node = ecore_list_current(list)) &&
|
||||
node->key != key)
|
||||
ecore_list_next(list);
|
||||
}
|
||||
|
||||
if (node) {
|
||||
ecore_list_remove(list);
|
||||
|
||||
ret = node->value;
|
||||
FREE(node);
|
||||
}
|
||||
}
|
||||
|
||||
if (ECORE_HASH_REDUCE(hash))
|
||||
_ecore_hash_decrease(hash);
|
||||
|
||||
ECORE_WRITE_UNLOCK(hash);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Description: Retrieve the node associated with key
|
||||
* Parameters: 1. hash - the hash table to search for the key
|
||||
* 2. key - the key to search for in the hash table
|
||||
* Returns: NULL on error, node corresponding to key on success
|
||||
*/
|
||||
static Ecore_Hash_Node *
|
||||
_ecore_hash_get_node(Ecore_Hash *hash, void *key)
|
||||
{
|
||||
unsigned int hash_val;
|
||||
Ecore_Hash_Node *node = NULL;
|
||||
|
||||
CHECK_PARAM_POINTER_RETURN("hash", hash, NULL);
|
||||
|
||||
ECORE_READ_LOCK(hash);
|
||||
|
||||
/* Compute the position in the table */
|
||||
if (!hash->hash_func)
|
||||
hash_val = (unsigned int)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_get_bucket(hash, hash->buckets[hash_val], key);
|
||||
|
||||
ECORE_READ_UNLOCK(hash);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
/*
|
||||
* Description: Search the hash bucket for a specified key
|
||||
* Parameters: 1. hash - the hash table to retrieve the comparison function
|
||||
* 2. bucket - the list to search for the key
|
||||
* 3. key - the key to search for in the list
|
||||
* Returns: NULL on error or not found, the found node on success
|
||||
*/
|
||||
inline Ecore_Hash_Node *
|
||||
_ecore_hash_get_bucket(Ecore_Hash *hash, Ecore_List *bucket, void *key)
|
||||
{
|
||||
Ecore_Hash_Node *node = NULL;
|
||||
|
||||
ECORE_READ_LOCK(hash);
|
||||
ecore_list_goto_first(bucket);
|
||||
|
||||
/*
|
||||
* Traverse the list to find the desired node, if the node is in the
|
||||
* list, then return the node.
|
||||
*/
|
||||
if (hash->compare) {
|
||||
while ((node = ecore_list_next(bucket)) != NULL) {
|
||||
ECORE_READ_LOCK(node);
|
||||
if (hash->compare(node->key, key) == 0) {
|
||||
ECORE_READ_UNLOCK(node);
|
||||
ECORE_READ_UNLOCK(hash);
|
||||
return node;
|
||||
}
|
||||
ECORE_READ_UNLOCK(node);
|
||||
}
|
||||
}
|
||||
else {
|
||||
while ((node = ecore_list_next(bucket)) != NULL) {
|
||||
ECORE_READ_LOCK(node);
|
||||
if (node->key == key) {
|
||||
ECORE_READ_UNLOCK(node);
|
||||
ECORE_READ_UNLOCK(hash);
|
||||
return node;
|
||||
}
|
||||
ECORE_READ_UNLOCK(node);
|
||||
}
|
||||
}
|
||||
ECORE_READ_UNLOCK(hash);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Description: Increase the size of the hash table by approx. 2 * current size
|
||||
* Parameters: 1. hash - the hash table to increase the size of
|
||||
* 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 (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 = (Ecore_List **)calloc(ecore_prime_table[hash->size],
|
||||
sizeof(Ecore_List *));
|
||||
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
/*
|
||||
* Description: Decrease the size of the hash table by < 1/2 * current size
|
||||
* Parameters: 1. hash - the hash table to decrease the size of
|
||||
* Returns: TRUE on success, FALSE on error
|
||||
*/
|
||||
static int
|
||||
_ecore_hash_decrease(Ecore_Hash *hash)
|
||||
{
|
||||
Ecore_List **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_List **)malloc(ecore_prime_table[hash->size] *
|
||||
sizeof(Ecore_List *));
|
||||
|
||||
/*
|
||||
* Make sure allocation succeeded otherwise rreturn to the previous
|
||||
* state
|
||||
*/
|
||||
if (!hash->buckets) {
|
||||
hash->buckets = old;
|
||||
hash->size++;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Zero out the new area
|
||||
*/
|
||||
memset(hash->buckets, 0, ecore_prime_table[hash->size]
|
||||
* sizeof(Ecore_List *));
|
||||
hash->nodes = 0;
|
||||
|
||||
if (_ecore_hash_rehash(hash, old, hash->size - 1)) {
|
||||
FREE(old);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Description: Rehash the nodes of a table into the hash table
|
||||
* Parameters: 1. hash - the hash to place the nodes of the table
|
||||
* 2. table - the table to remove the nodes from and place in hash
|
||||
* Returns: TRUE on success, FALSE on success
|
||||
*/
|
||||
inline int
|
||||
_ecore_hash_rehash(Ecore_Hash *hash, Ecore_List **old_table, int old_size)
|
||||
{
|
||||
int i;
|
||||
Ecore_Hash_Node *node;
|
||||
Ecore_List *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 */
|
||||
old = old_table[i];
|
||||
old_table[i] = NULL;
|
||||
|
||||
/* Loop through re-adding each node to the hash table */
|
||||
while (old && (node = ecore_list_remove_last(old))) {
|
||||
_ecore_hash_add_node(hash, node);
|
||||
}
|
||||
|
||||
/* Now free up the old list space */
|
||||
if (old)
|
||||
ecore_list_destroy(old);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Description: Create a new hash node for key and value storage
|
||||
* Parameters: 1. key - the key for this node
|
||||
* 2. value - the value that the key references
|
||||
* 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;
|
||||
}
|
||||
|
||||
/*
|
||||
* Description: Initialize a hash node to some sane default values
|
||||
* Parameters: 1. node - the node to set the values
|
||||
* 2. key - the key to reference this node
|
||||
* 3. value - the value that key refers to
|
||||
* 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);
|
||||
|
||||
ECORE_INIT_LOCKS(node);
|
||||
node->key = key;
|
||||
node->value = value;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Description: Destroy a node and call the specified callbacks to free data
|
||||
* Parameters: 1. node - the node to be destroyed
|
||||
* 2. keyd - the function to free the key
|
||||
* 3. valued - the function to free the value
|
||||
* 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;
|
||||
}
|
|
@ -75,9 +75,9 @@ _ecore_idle_enterer_shutdown(void)
|
|||
void
|
||||
_ecore_idle_enterer_call(void)
|
||||
{
|
||||
Ecore_List *l;
|
||||
Ecore_Oldlist *l;
|
||||
|
||||
for (l = (Ecore_List *)idle_enterers; l; l = l->next)
|
||||
for (l = (Ecore_Oldlist *)idle_enterers; l; l = l->next)
|
||||
{
|
||||
Ecore_Idle_Enterer *ie;
|
||||
|
||||
|
@ -89,7 +89,7 @@ _ecore_idle_enterer_call(void)
|
|||
}
|
||||
if (idle_enterers_delete_me)
|
||||
{
|
||||
for (l = (Ecore_List *)idle_enterers; l;)
|
||||
for (l = (Ecore_Oldlist *)idle_enterers; l;)
|
||||
{
|
||||
Ecore_Idle_Enterer *ie;
|
||||
|
||||
|
|
|
@ -72,9 +72,9 @@ _ecore_idle_exiter_shutdown(void)
|
|||
void
|
||||
_ecore_idle_exiter_call(void)
|
||||
{
|
||||
Ecore_List *l;
|
||||
Ecore_Oldlist *l;
|
||||
|
||||
for (l = (Ecore_List *)idle_exiters; l; l = l->next)
|
||||
for (l = (Ecore_Oldlist *)idle_exiters; l; l = l->next)
|
||||
{
|
||||
Ecore_Idle_Exiter *ie;
|
||||
|
||||
|
@ -86,7 +86,7 @@ _ecore_idle_exiter_call(void)
|
|||
}
|
||||
if (idle_exiters_delete_me)
|
||||
{
|
||||
for (l = (Ecore_List *)idle_exiters; l;)
|
||||
for (l = (Ecore_Oldlist *)idle_exiters; l;)
|
||||
{
|
||||
Ecore_Idle_Exiter *ie;
|
||||
|
||||
|
|
|
@ -76,9 +76,9 @@ _ecore_idler_shutdown(void)
|
|||
int
|
||||
_ecore_idler_call(void)
|
||||
{
|
||||
Ecore_List *l;
|
||||
Ecore_Oldlist *l;
|
||||
|
||||
for (l = (Ecore_List *)idlers; l; l = l->next)
|
||||
for (l = (Ecore_Oldlist *)idlers; l; l = l->next)
|
||||
{
|
||||
Ecore_Idler *ie;
|
||||
|
||||
|
@ -90,7 +90,7 @@ _ecore_idler_call(void)
|
|||
}
|
||||
if (idlers_delete_me)
|
||||
{
|
||||
for (l = (Ecore_List *)idlers; l;)
|
||||
for (l = (Ecore_Oldlist *)idlers; l;)
|
||||
{
|
||||
Ecore_Idler *ie;
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -239,7 +239,7 @@ _ecore_main_select(double timeout)
|
|||
fd_set rfds, wfds, exfds;
|
||||
int max_fd;
|
||||
int ret;
|
||||
Ecore_List *l;
|
||||
Ecore_Oldlist *l;
|
||||
|
||||
t = NULL;
|
||||
if (timeout > 0.0)
|
||||
|
@ -262,7 +262,7 @@ _ecore_main_select(double timeout)
|
|||
FD_ZERO(&rfds);
|
||||
FD_ZERO(&wfds);
|
||||
FD_ZERO(&exfds);
|
||||
for (l = (Ecore_List *)fd_handlers; l; l = l->next)
|
||||
for (l = (Ecore_Oldlist *)fd_handlers; l; l = l->next)
|
||||
{
|
||||
Ecore_Fd_Handler *fdh;
|
||||
|
||||
|
@ -291,7 +291,7 @@ _ecore_main_select(double timeout)
|
|||
}
|
||||
if (ret > 0)
|
||||
{
|
||||
for (l = (Ecore_List *)fd_handlers; l; l = l->next)
|
||||
for (l = (Ecore_Oldlist *)fd_handlers; l; l = l->next)
|
||||
{
|
||||
Ecore_Fd_Handler *fdh;
|
||||
|
||||
|
@ -315,10 +315,10 @@ _ecore_main_select(double timeout)
|
|||
static void
|
||||
_ecore_main_fd_handlers_cleanup(void)
|
||||
{
|
||||
Ecore_List *l;
|
||||
Ecore_Oldlist *l;
|
||||
|
||||
if (!fd_handlers_delete_me) return;
|
||||
for (l = (Ecore_List *)fd_handlers; l;)
|
||||
for (l = (Ecore_Oldlist *)fd_handlers; l;)
|
||||
{
|
||||
Ecore_Fd_Handler *fdh;
|
||||
|
||||
|
@ -337,9 +337,9 @@ _ecore_main_fd_handlers_cleanup(void)
|
|||
static void
|
||||
_ecore_main_fd_handlers_call(void)
|
||||
{
|
||||
Ecore_List *l;
|
||||
Ecore_Oldlist *l;
|
||||
|
||||
for (l = (Ecore_List *)fd_handlers; l; l = l->next)
|
||||
for (l = (Ecore_Oldlist *)fd_handlers; l; l = l->next)
|
||||
{
|
||||
Ecore_Fd_Handler *fdh;
|
||||
|
||||
|
@ -366,11 +366,11 @@ _ecore_main_fd_handlers_call(void)
|
|||
static int
|
||||
_ecore_main_fd_handlers_buf_call(void)
|
||||
{
|
||||
Ecore_List *l;
|
||||
Ecore_Oldlist *l;
|
||||
int ret;
|
||||
|
||||
ret = 0;
|
||||
for (l = (Ecore_List *)fd_handlers; l; l = l->next)
|
||||
for (l = (Ecore_Oldlist *)fd_handlers; l; l = l->next)
|
||||
{
|
||||
Ecore_Fd_Handler *fdh;
|
||||
|
||||
|
|
|
@ -0,0 +1,276 @@
|
|||
#include <Ecore.h>
|
||||
|
||||
static Ecore_List *group_list = NULL;
|
||||
|
||||
Ecore_Path_Group *__ecore_path_group_find(char *name);
|
||||
Ecore_Path_Group *__ecore_path_group_find_id(int id);
|
||||
|
||||
/**
|
||||
* ecore_path_group_new - create a new path group
|
||||
* @group_name: the name of the new group
|
||||
*
|
||||
* Returns 0 on error, the integer id of the new group on success.
|
||||
*/
|
||||
int
|
||||
ecore_path_group_new(char *group_name)
|
||||
{
|
||||
Ecore_Path_Group *last;
|
||||
Ecore_Path_Group *group;
|
||||
|
||||
CHECK_PARAM_POINTER_RETURN("group_name", group_name, -1);
|
||||
|
||||
if (!group_list) {
|
||||
group_list = ecore_list_new();
|
||||
}
|
||||
else {
|
||||
group = __ecore_path_group_find(group_name);
|
||||
if (group)
|
||||
return -1;
|
||||
}
|
||||
|
||||
group = (Ecore_Path_Group *)malloc(sizeof(Ecore_Path_Group));
|
||||
memset(group, 0, sizeof(Ecore_Path_Group));
|
||||
|
||||
group->name = strdup(group_name);
|
||||
ecore_list_append(group_list, group);
|
||||
|
||||
last = ecore_list_goto_last(group_list);
|
||||
group->id = last->id + 1;
|
||||
|
||||
return group->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* ecore_path_group_del - destroy a previously created path group
|
||||
* @group_id: the unique identifier for the group
|
||||
*
|
||||
* Returns no value.
|
||||
*/
|
||||
void
|
||||
ecore_path_group_del(int group_id)
|
||||
{
|
||||
Ecore_Path_Group *group;
|
||||
|
||||
group = __ecore_path_group_find_id(group_id);
|
||||
|
||||
if (!group)
|
||||
return;
|
||||
|
||||
if (group->paths) {
|
||||
ecore_list_for_each(group->paths,
|
||||
ECORE_FOR_EACH(free));
|
||||
ecore_list_destroy(group->paths);
|
||||
}
|
||||
|
||||
free(group->name);
|
||||
free(group);
|
||||
}
|
||||
|
||||
/**
|
||||
* ecore_path_group_add - add a directory to be searched for files
|
||||
* @group_id: the unique identifier for the group to add the path
|
||||
* @path: the new path to be added to the group
|
||||
*
|
||||
* Returns no value.
|
||||
*/
|
||||
void
|
||||
ecore_path_group_add(int group_id, char *path)
|
||||
{
|
||||
Ecore_Path_Group *group;
|
||||
|
||||
CHECK_PARAM_POINTER("path", path);
|
||||
|
||||
group = __ecore_path_group_find_id(group_id);
|
||||
|
||||
if (!group)
|
||||
return;
|
||||
|
||||
if (!group->paths)
|
||||
group->paths = ecore_list_new();
|
||||
|
||||
ecore_list_append(group->paths, strdup(path));
|
||||
}
|
||||
|
||||
/**
|
||||
* ecore_path_group_remove - remove a directory to be searched for files
|
||||
* @group_id: the identifier for the group to remove a path
|
||||
* @path: the path to be removed from @group_id
|
||||
*
|
||||
* Returns no value. Removes @path from the list of directories to search for
|
||||
* files.
|
||||
*/
|
||||
void
|
||||
ecore_path_group_remove(int group_id, char *path)
|
||||
{
|
||||
char *found;
|
||||
Ecore_Path_Group *group;
|
||||
|
||||
CHECK_PARAM_POINTER("path", path);
|
||||
|
||||
group = __ecore_path_group_find_id(group_id);
|
||||
|
||||
if (!group || !group->paths)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Find the path in the list of available paths
|
||||
*/
|
||||
ecore_list_goto_first(group->paths);
|
||||
|
||||
while ((found = ecore_list_current(group->paths))
|
||||
&& strcmp(found, path))
|
||||
ecore_list_next(group->paths);
|
||||
|
||||
/*
|
||||
* If the path is found, remove and free it
|
||||
*/
|
||||
if (found) {
|
||||
ecore_list_remove(group->paths);
|
||||
free(found);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ecore_path_group_find - find a file in a group of paths
|
||||
* @group_id - the path group id to search for @file
|
||||
* @file: the name of the file to find in the path group @group_id
|
||||
*
|
||||
* Returns a pointer to a newly allocated path location of the found file
|
||||
* on success, NULL on failure.
|
||||
*/
|
||||
char *
|
||||
ecore_path_group_find(int group_id, char *name)
|
||||
{
|
||||
char *p;
|
||||
struct stat st;
|
||||
char path[PATH_MAX];
|
||||
Ecore_Path_Group *group;
|
||||
|
||||
CHECK_PARAM_POINTER_RETURN("name", name, NULL);
|
||||
|
||||
group = __ecore_path_group_find_id(group_id);
|
||||
|
||||
/*
|
||||
* Search the paths of the path group for the specified file name
|
||||
*/
|
||||
ecore_list_goto_first(group->paths);
|
||||
p = ecore_list_next(group->paths);
|
||||
do {
|
||||
snprintf(path, PATH_MAX, "%s/%s", p, name);
|
||||
stat(path, &st);
|
||||
} while (!S_ISREG(st.st_mode) && (p = ecore_list_next(group->paths)));
|
||||
|
||||
if (p)
|
||||
p = strdup(path);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
/**
|
||||
* ecore_path_group_available - get a list of all available files in the path
|
||||
* @group_id: the identifier for the path to get all available files
|
||||
*
|
||||
* Returns a pointer to a newly allocated list of all files found in the paths
|
||||
* identified by @group_id, NULL on failure.
|
||||
*/
|
||||
Ecore_List *
|
||||
ecore_path_group_available(int group_id)
|
||||
{
|
||||
Ecore_List *avail = NULL;
|
||||
Ecore_Path_Group *group;
|
||||
char *path;
|
||||
|
||||
group = __ecore_path_group_find_id(group_id);
|
||||
|
||||
if (!group || !group->paths || ecore_list_is_empty(group->paths))
|
||||
return NULL;
|
||||
|
||||
ecore_list_goto_first(group->paths);
|
||||
|
||||
while ((path = ecore_list_next(group->paths)) != NULL)
|
||||
{
|
||||
DIR *dir;
|
||||
struct stat st;
|
||||
struct dirent *d;
|
||||
|
||||
stat(path, &st);
|
||||
|
||||
if (!S_ISDIR(st.st_mode))
|
||||
continue;
|
||||
|
||||
dir = opendir(path);
|
||||
|
||||
if (!dir)
|
||||
continue;
|
||||
|
||||
while ((d = readdir(dir)) != NULL)
|
||||
{
|
||||
char ppath[PATH_MAX];
|
||||
char *ext;
|
||||
char n[PATH_MAX];
|
||||
int l;
|
||||
|
||||
if (!strncmp(d->d_name, ".", 1))
|
||||
continue;
|
||||
|
||||
ext = strrchr(d->d_name, '.');
|
||||
|
||||
if (!ext || strncmp(ext, ".so", 3))
|
||||
continue;
|
||||
|
||||
snprintf(ppath, PATH_MAX, "%s/%s", path, d->d_name);
|
||||
|
||||
stat(ppath, &st);
|
||||
|
||||
if (!S_ISREG(st.st_mode))
|
||||
continue;
|
||||
|
||||
l = strlen(d->d_name);
|
||||
|
||||
strncpy(n, d->d_name, l - 2);
|
||||
|
||||
if (!avail)
|
||||
avail = ecore_list_new();
|
||||
|
||||
ecore_list_append(avail, strdup(n));
|
||||
}
|
||||
}
|
||||
|
||||
return avail;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find the specified group name
|
||||
*/
|
||||
Ecore_Path_Group *
|
||||
__ecore_path_group_find(char *name)
|
||||
{
|
||||
Ecore_Path_Group *group;
|
||||
|
||||
CHECK_PARAM_POINTER_RETURN("name", name, NULL);
|
||||
|
||||
ecore_list_goto_first(group_list);
|
||||
|
||||
while ((group = ecore_list_next(group_list)) != NULL)
|
||||
if (!strcmp(group->name, name))
|
||||
return group;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find the specified group id
|
||||
*/
|
||||
Ecore_Path_Group *
|
||||
__ecore_path_group_find_id(int id)
|
||||
{
|
||||
Ecore_Path_Group *group;
|
||||
|
||||
ecore_list_goto_first(group_list);
|
||||
|
||||
while ((group = ecore_list_next(group_list)) != NULL)
|
||||
if (group->id == id)
|
||||
return group;
|
||||
|
||||
return NULL;
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
#include <Ecore.h>
|
||||
|
||||
static Ecore_List *loaded_plugins = NULL;
|
||||
|
||||
/**
|
||||
* ecore_plugin_load - load the specified plugin from the specified path group
|
||||
* @group_id: the path group to search for the plugin to load
|
||||
* @plugin_name: the name of the plugin to load
|
||||
*
|
||||
* Returns a pointer to the newly loaded plugin on success, NULL on failure.
|
||||
*/
|
||||
Ecore_Plugin *
|
||||
ecore_plugin_load(int group_id, char *plugin_name)
|
||||
{
|
||||
char *path;
|
||||
char temp[PATH_MAX];
|
||||
|
||||
Ecore_Plugin *plugin;
|
||||
void *handle = NULL;
|
||||
|
||||
CHECK_PARAM_POINTER_RETURN("plugin_name", plugin_name, NULL);
|
||||
|
||||
snprintf(temp, PATH_MAX, "%s.so", plugin_name);
|
||||
path = ecore_path_group_find(group_id, temp);
|
||||
if (!path)
|
||||
return NULL;
|
||||
|
||||
handle = dlopen(path, RTLD_LAZY);
|
||||
if (!handle)
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* Allocate the new plugin and initialize it's fields
|
||||
*/
|
||||
plugin = malloc(sizeof(Ecore_Plugin));
|
||||
memset(plugin, 0, sizeof(Ecore_Plugin));
|
||||
|
||||
plugin->group = group_id;
|
||||
plugin->name = strdup(plugin_name);
|
||||
plugin->handle = handle;
|
||||
|
||||
/*
|
||||
* Now add it to the list of the groups loaded plugins
|
||||
*/
|
||||
if (!loaded_plugins)
|
||||
loaded_plugins = ecore_list_new();
|
||||
|
||||
ecore_list_append(loaded_plugins, plugin);
|
||||
|
||||
FREE(path);
|
||||
|
||||
return plugin;
|
||||
}
|
||||
|
||||
/**
|
||||
* ecore_plugin_unload - unload the specified plugin
|
||||
* @plugin: the plugin to unload from memory
|
||||
*
|
||||
* Returns no value.
|
||||
*/
|
||||
void
|
||||
ecore_plugin_unload(Ecore_Plugin * plugin)
|
||||
{
|
||||
CHECK_PARAM_POINTER("plugin", plugin);
|
||||
|
||||
if (!plugin->handle)
|
||||
return;
|
||||
|
||||
if (ecore_list_goto(loaded_plugins, plugin))
|
||||
ecore_list_remove(loaded_plugins);
|
||||
|
||||
dlclose(plugin->handle);
|
||||
|
||||
FREE(plugin->name);
|
||||
FREE(plugin);
|
||||
}
|
||||
|
||||
/*
|
||||
* Lookup the specified symbol for the plugin
|
||||
*/
|
||||
void *
|
||||
ecore_plugin_call(Ecore_Plugin * plugin, char *symbol_name)
|
||||
{
|
||||
void *ret;
|
||||
|
||||
CHECK_PARAM_POINTER_RETURN("plugin", plugin, NULL);
|
||||
CHECK_PARAM_POINTER_RETURN("symbol_name", symbol_name, NULL);
|
||||
|
||||
if (!plugin->handle)
|
||||
return NULL;
|
||||
|
||||
ret = dlsym(plugin->handle, symbol_name);
|
||||
|
||||
return ret;
|
||||
}
|
|
@ -31,12 +31,12 @@
|
|||
|
||||
typedef int Ecore_Magic;
|
||||
|
||||
typedef struct _Ecore_List Ecore_List;
|
||||
typedef struct _Ecore_Oldlist Ecore_Oldlist;
|
||||
|
||||
struct _Ecore_List
|
||||
struct _Ecore_Oldlist
|
||||
{
|
||||
Ecore_List *next, *prev;
|
||||
Ecore_List *last;
|
||||
Ecore_Oldlist *next, *prev;
|
||||
Ecore_Oldlist *last;
|
||||
};
|
||||
|
||||
#ifndef _ECORE_H
|
||||
|
@ -60,7 +60,7 @@ typedef struct _Ecore_Event Ecore_Event;
|
|||
|
||||
struct _Ecore_Exe
|
||||
{
|
||||
Ecore_List __list_data;
|
||||
Ecore_Oldlist __list_data;
|
||||
ECORE_MAGIC;
|
||||
pid_t pid;
|
||||
void *data;
|
||||
|
@ -68,7 +68,7 @@ struct _Ecore_Exe
|
|||
|
||||
struct _Ecore_Timer
|
||||
{
|
||||
Ecore_List __list_data;
|
||||
Ecore_Oldlist __list_data;
|
||||
ECORE_MAGIC;
|
||||
double in;
|
||||
double at;
|
||||
|
@ -80,7 +80,7 @@ struct _Ecore_Timer
|
|||
|
||||
struct _Ecore_Idler
|
||||
{
|
||||
Ecore_List __list_data;
|
||||
Ecore_Oldlist __list_data;
|
||||
ECORE_MAGIC;
|
||||
int delete_me : 1;
|
||||
int (*func) (void *data);
|
||||
|
@ -89,7 +89,7 @@ struct _Ecore_Idler
|
|||
|
||||
struct _Ecore_Idle_Enterer
|
||||
{
|
||||
Ecore_List __list_data;
|
||||
Ecore_Oldlist __list_data;
|
||||
ECORE_MAGIC;
|
||||
int delete_me : 1;
|
||||
int (*func) (void *data);
|
||||
|
@ -98,7 +98,7 @@ struct _Ecore_Idle_Enterer
|
|||
|
||||
struct _Ecore_Idle_Exiter
|
||||
{
|
||||
Ecore_List __list_data;
|
||||
Ecore_Oldlist __list_data;
|
||||
ECORE_MAGIC;
|
||||
int delete_me : 1;
|
||||
int (*func) (void *data);
|
||||
|
@ -107,7 +107,7 @@ struct _Ecore_Idle_Exiter
|
|||
|
||||
struct _Ecore_Fd_Handler
|
||||
{
|
||||
Ecore_List __list_data;
|
||||
Ecore_Oldlist __list_data;
|
||||
ECORE_MAGIC;
|
||||
int fd;
|
||||
Ecore_Fd_Handler_Flags flags;
|
||||
|
@ -123,7 +123,7 @@ struct _Ecore_Fd_Handler
|
|||
|
||||
struct _Ecore_Event_Handler
|
||||
{
|
||||
Ecore_List __list_data;
|
||||
Ecore_Oldlist __list_data;
|
||||
ECORE_MAGIC;
|
||||
int type;
|
||||
int delete_me : 1;
|
||||
|
@ -133,7 +133,7 @@ struct _Ecore_Event_Handler
|
|||
|
||||
struct _Ecore_Event_Filter
|
||||
{
|
||||
Ecore_List __list_data;
|
||||
Ecore_Oldlist __list_data;
|
||||
ECORE_MAGIC;
|
||||
int delete_me : 1;
|
||||
void * (*func_start) (void *data);
|
||||
|
@ -145,7 +145,7 @@ struct _Ecore_Event_Filter
|
|||
|
||||
struct _Ecore_Event
|
||||
{
|
||||
Ecore_List __list_data;
|
||||
Ecore_Oldlist __list_data;
|
||||
ECORE_MAGIC;
|
||||
int type;
|
||||
void *event;
|
||||
|
|
|
@ -0,0 +1,402 @@
|
|||
#include <Ecore.h>
|
||||
|
||||
static void _ecore_sheap_heapify(Ecore_Sheap *heap, int i);
|
||||
static void _ecore_sheap_update_data(Ecore_Sheap *heap);
|
||||
|
||||
/**
|
||||
* ecore_sheap_new - allocate and initialize a new binary heap
|
||||
* @compare: the function for comparing keys, NULL for direct comparison
|
||||
* @size: the number of elements to allow in the heap
|
||||
*
|
||||
* Returns a pointer to the newly allocated binary heap on success, NULL on
|
||||
* failure.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* ecore_sheap_init - initialize a binary heap to default values
|
||||
* @heap: the heap to initialize
|
||||
* @compare: the function for comparing keys, NULL for direct comparison
|
||||
* @size: the number of elements to allow in the heap
|
||||
*
|
||||
* Returns TRUE on success, FALSE on failure
|
||||
*/
|
||||
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_SHEAP_MIN;
|
||||
|
||||
heap->data = (void **)malloc(heap->space * sizeof(void *));
|
||||
if (!heap->data)
|
||||
return FALSE;
|
||||
memset(heap->data, 0, heap->space * sizeof(void *));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* ecore_sheap_destroy - free up the memory used by the heap
|
||||
* @heap: the heap to be freed
|
||||
*
|
||||
* Returns no value. Free's the memory used by @heap, calls the destroy
|
||||
* function on each data item if necessary.
|
||||
*/
|
||||
void ecore_sheap_destroy(Ecore_Sheap *heap)
|
||||
{
|
||||
CHECK_PARAM_POINTER("heap", heap);
|
||||
|
||||
/*
|
||||
* FIXME: Need to setup destructor callbacks for this class.
|
||||
*/
|
||||
FREE(heap->data);
|
||||
|
||||
FREE(heap);
|
||||
}
|
||||
|
||||
/**
|
||||
* ecore_sheap_insert - insert new data into the heap
|
||||
* @heap: the heap to insert @data
|
||||
* @data: the data to add to @heap
|
||||
*
|
||||
* Returns TRUE on success, NULL on failure. Increases the size of the heap if
|
||||
* it becomes larger than available space.
|
||||
*/
|
||||
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_SHEAP_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;
|
||||
}
|
||||
|
||||
/**
|
||||
* ecore_sheap_extract - extract the item at the top of the heap
|
||||
* @heap: the heap to remove the top item
|
||||
*
|
||||
* Returns the top item of the heap on success, NULL on failure. The extract
|
||||
* function maintains the heap properties after the extract.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* ecore_sheap_extreme - examine the item at the top of the heap
|
||||
* @heap: the heap to examine the top item
|
||||
*
|
||||
* Returns the top item of the heap on success, NULL on failure. The function
|
||||
* does not alter the heap.
|
||||
*/
|
||||
void *ecore_sheap_extreme(Ecore_Sheap *heap)
|
||||
{
|
||||
if (heap->size < 1)
|
||||
return NULL;
|
||||
|
||||
return heap->data[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* ecore_sheap_change - change the value of the specified item in the heap
|
||||
* @heap: the heap to search for the item to change
|
||||
* @item: the item in the heap to change
|
||||
* @newval: the new value assigned to the item in the heap
|
||||
*
|
||||
* Returns TRUE on success, FALSE on failure. The heap does not free the old
|
||||
* data since it must be passed in, so the caller can perform the free if
|
||||
* desired.
|
||||
*/
|
||||
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->data[i] != item; heap++);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* ecore_sheap_set_compare - change the comparison function for the heap
|
||||
* @heap: the heap to change comparison function
|
||||
* @compare: the new function for comparing nodes
|
||||
*
|
||||
* Returns TRUE on success, FALSE on failure. The comparison function is
|
||||
* changed to @compare and the heap is heapified by the new comparison.
|
||||
*/
|
||||
int ecore_sheap_set_compare(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;
|
||||
}
|
||||
|
||||
/**
|
||||
* ecore_sheap_set_order - change the order of the heap
|
||||
* @heap: the heap to change the order
|
||||
* @order: the new order of the heap
|
||||
*
|
||||
* Returns no value. Changes the heap order of @heap and re-heapifies the data
|
||||
* to this new order. The default order is a min heap.
|
||||
*/
|
||||
void ecore_sheap_set_order(Ecore_Sheap *heap, char order)
|
||||
{
|
||||
CHECK_PARAM_POINTER("heap", heap);
|
||||
|
||||
heap->order = order;
|
||||
|
||||
_ecore_sheap_update_data(heap);
|
||||
}
|
||||
|
||||
/**
|
||||
* ecore_sheap_sort - sort the data in the heap
|
||||
* @heap: the heap to be sorted
|
||||
*
|
||||
* Returns no value. Sorts the data in the heap into the order that is used
|
||||
* for the heap's data.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* ecore_sheap_item - access the item at the ith position in the heap
|
||||
* @heap: the heap to access the internal data
|
||||
* @i: the index of the data within the heap
|
||||
*
|
||||
* Returns the data located at the ith position within @heap on success, NULL
|
||||
* on failure. The data is guaranteed to be in sorted order.
|
||||
*/
|
||||
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];
|
||||
}
|
||||
|
||||
/*
|
||||
* _ecore_sheap_heapify - regain the heap properties starting at position i
|
||||
* @heap: the heap to regain heap properties
|
||||
* @i: the position to start heapifying
|
||||
*
|
||||
* Returns no value.
|
||||
*/
|
||||
static void _ecore_sheap_heapify(Ecore_Sheap *heap, int i)
|
||||
{
|
||||
int extreme;
|
||||
int left = LEFT(i);
|
||||
int right = RIGHT(i);
|
||||
|
||||
if (heap->order == ECORE_SHEAP_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);
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
#include <Ecore.h>
|
||||
|
||||
static Ecore_Hash *ecore_strings = NULL;
|
||||
|
||||
/**
|
||||
* ecore_stringinstance - retrieve an instance of a string for use in an ecore
|
||||
* @string: the string to retrieve an instance
|
||||
*
|
||||
* Returns a pointer to a the string on success, NULL on failure.
|
||||
*/
|
||||
char *ecore_string_instance(char *string)
|
||||
{
|
||||
Ecore_String *str;
|
||||
|
||||
CHECK_PARAM_POINTER_RETURN("string", string, NULL);
|
||||
|
||||
/*
|
||||
* No strings have been loaded at this point, so create the hash
|
||||
* table for storing string info for later.
|
||||
*/
|
||||
if (!ecore_strings)
|
||||
ecore_strings = ecore_hash_new(ecore_str_hash, ecore_str_compare);
|
||||
|
||||
/*
|
||||
* Check for a previous instance of the string, if not found, create
|
||||
* it.
|
||||
*/
|
||||
str = ecore_hash_get(ecore_strings, string);
|
||||
if (!str) {
|
||||
|
||||
/*
|
||||
* Allocate and initialize a new string reference.
|
||||
*/
|
||||
str = (Ecore_String *)malloc(sizeof(Ecore_String));
|
||||
|
||||
str->string = strdup(string);
|
||||
str->references = 0;
|
||||
|
||||
ecore_hash_set(ecore_strings, string, str);
|
||||
}
|
||||
|
||||
str->references++;
|
||||
|
||||
return str->string;
|
||||
}
|
||||
|
||||
/**
|
||||
* ecore_string_release - release an instance of a string
|
||||
* @string: the string to release an instance
|
||||
*
|
||||
* Returns no value. Marks the string as losing an instance, will free the
|
||||
* string if no other instances are present.
|
||||
*/
|
||||
void ecore_string_release(char *string)
|
||||
{
|
||||
Ecore_String *str;
|
||||
|
||||
CHECK_PARAM_POINTER("string", string);
|
||||
|
||||
str = ecore_hash_get(ecore_strings, string);
|
||||
if (!str)
|
||||
return;
|
||||
|
||||
str->references--;
|
||||
if (str->references < 1) {
|
||||
ecore_hash_remove(ecore_strings, string);
|
||||
FREE(str->string);
|
||||
}
|
||||
}
|
|
@ -124,10 +124,10 @@ _ecore_timer_shutdown(void)
|
|||
void
|
||||
_ecore_timer_cleanup(void)
|
||||
{
|
||||
Ecore_List *l;
|
||||
Ecore_Oldlist *l;
|
||||
|
||||
if (!timers_delete_me) return;
|
||||
for (l = (Ecore_List *)timers; l;)
|
||||
for (l = (Ecore_Oldlist *)timers; l;)
|
||||
{
|
||||
Ecore_Timer *timer;
|
||||
|
||||
|
@ -148,11 +148,11 @@ _ecore_timer_cleanup(void)
|
|||
void
|
||||
_ecore_timer_enable_new(void)
|
||||
{
|
||||
Ecore_List *l;
|
||||
Ecore_Oldlist *l;
|
||||
|
||||
if (!timers_added) return;
|
||||
timers_added = 0;
|
||||
for (l = (Ecore_List *)timers; l; l = l->next)
|
||||
for (l = (Ecore_Oldlist *)timers; l; l = l->next)
|
||||
{
|
||||
Ecore_Timer *timer;
|
||||
|
||||
|
@ -177,11 +177,11 @@ _ecore_timer_next_get(void)
|
|||
int
|
||||
_ecore_timer_call(double when)
|
||||
{
|
||||
Ecore_List *l;
|
||||
Ecore_Oldlist *l;
|
||||
Ecore_Timer *timer;
|
||||
|
||||
if (!timers) return 0;
|
||||
for (l = (Ecore_List *)timers; l; l = l->next)
|
||||
for (l = (Ecore_Oldlist *)timers; l; l = l->next)
|
||||
{
|
||||
timer = (Ecore_Timer *)l;
|
||||
if ((timer->at <= when) &&
|
||||
|
@ -203,7 +203,7 @@ _ecore_timer_call(double when)
|
|||
static void
|
||||
_ecore_timer_set(Ecore_Timer *timer, double at, double in, int (*func) (void *data), void *data)
|
||||
{
|
||||
Ecore_List *l;
|
||||
Ecore_Oldlist *l;
|
||||
|
||||
timers_added = 1;
|
||||
timer->at = at;
|
||||
|
@ -213,7 +213,7 @@ _ecore_timer_set(Ecore_Timer *timer, double at, double in, int (*func) (void *da
|
|||
timer->just_added = 1;
|
||||
if (timers)
|
||||
{
|
||||
for (l = ((Ecore_List *)(timers))->last; l; l = l->prev)
|
||||
for (l = ((Ecore_Oldlist *)(timers))->last; l; l = l->prev)
|
||||
{
|
||||
Ecore_Timer *t2;
|
||||
|
||||
|
|
|
@ -0,0 +1,852 @@
|
|||
/* ecore_tree.c
|
||||
|
||||
Copyright (C) 2001 Nathan Ingersoll <ningerso@d.umn.edu>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to
|
||||
deal in the Software without restriction, including without limitation the
|
||||
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
sell copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies of the Software and its documentation and acknowledgment shall be
|
||||
given in the documentation and software packages that this Software was
|
||||
used.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#include <Ecore.h>
|
||||
|
||||
/* A macro for determining the highest node at given branch */
|
||||
#define MAX_HEIGHT(node) (node ? MAX(node->max_left, node->max_right) : 0)
|
||||
|
||||
/* Utility functions for searching the tree and returning a node, or its
|
||||
* parent */
|
||||
Ecore_Tree_Node *tree_node_find(Ecore_Tree * tree, void *key);
|
||||
Ecore_Tree_Node *tree_node_find_parent(Ecore_Tree * tree, void *key);
|
||||
|
||||
/* Balancing functions, keep the tree balanced within a one node height
|
||||
* difference */
|
||||
int tree_node_balance(Ecore_Tree * Tree, Ecore_Tree_Node * top_node);
|
||||
int tree_node_rotate_right(Ecore_Tree * tree, Ecore_Tree_Node * top_node);
|
||||
int tree_node_rotate_left(Ecore_Tree * tree, Ecore_Tree_Node * top_node);
|
||||
|
||||
/* Fucntions for executing a specified function on each node of a tree */
|
||||
int tree_for_each_node(Ecore_Tree_Node * node, Ecore_For_Each for_each_func);
|
||||
int tree_for_each_node_value(Ecore_Tree_Node * node,
|
||||
Ecore_For_Each for_each_func);
|
||||
|
||||
/**
|
||||
* ecore_tree_new - allocate a new tree structure.
|
||||
* @compare_func: function used to compare the two values
|
||||
*
|
||||
* Returns NULL if the operation fails, otherwise a pointer to the new tree
|
||||
*/
|
||||
Ecore_Tree *ecore_tree_new(Ecore_Compare_Cb compare_func)
|
||||
{
|
||||
Ecore_Tree *new_tree;
|
||||
|
||||
new_tree = ECORE_TREE(malloc(sizeof(Ecore_Tree)));
|
||||
if (!new_tree)
|
||||
return NULL;
|
||||
|
||||
if (!ecore_tree_init(new_tree, compare_func)) {
|
||||
IF_FREE(new_tree);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return new_tree;
|
||||
}
|
||||
|
||||
/**
|
||||
* ecore_tree_init - initialize a tree structure to some sane initial values
|
||||
* @new_tree: the new tree structure to be initialized
|
||||
* @compare_func: the function used to compare node keys
|
||||
*
|
||||
* Returns TRUE on successful initialization, FALSE on an error
|
||||
*/
|
||||
int ecore_tree_init(Ecore_Tree * new_tree, Ecore_Compare_Cb compare_func)
|
||||
{
|
||||
CHECK_PARAM_POINTER_RETURN("new_tree", new_tree, FALSE);
|
||||
|
||||
memset(new_tree, 0, sizeof(Ecore_Tree));
|
||||
|
||||
if (!compare_func)
|
||||
new_tree->compare_func = ecore_direct_compare;
|
||||
else
|
||||
new_tree->compare_func = compare_func;
|
||||
|
||||
ECORE_INIT_LOCKS(new_tree);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* ecore_tree_set_free_cb - add a function to be called at node destroy time
|
||||
* @tree: the tree that will use this function when nodes are destroyed
|
||||
* @free_func - the function that will be passed the node being freed
|
||||
*
|
||||
* Returns TRUE on successful set, FALSE otherwise.
|
||||
*/
|
||||
int ecore_tree_set_free_cb(Ecore_Tree * tree, Ecore_Free_Cb free_func)
|
||||
{
|
||||
CHECK_PARAM_POINTER_RETURN("tree", tree, FALSE);
|
||||
|
||||
ECORE_WRITE_LOCK(tree);
|
||||
tree->free_func = free_func;
|
||||
ECORE_WRITE_UNLOCK(tree);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* ecore_tree_node_init - initialize a new tree node
|
||||
*
|
||||
* Returns FALSE if the operation fails, otherwise TRUE
|
||||
*/
|
||||
int ecore_tree_node_init(Ecore_Tree_Node * new_node)
|
||||
{
|
||||
CHECK_PARAM_POINTER_RETURN("new_node", new_node, FALSE);
|
||||
|
||||
new_node->key = NULL;
|
||||
new_node->value = NULL;
|
||||
|
||||
new_node->parent = NULL;
|
||||
new_node->right_child = NULL;
|
||||
new_node->left_child = NULL;
|
||||
|
||||
new_node->max_left = new_node->max_right = 0;
|
||||
|
||||
ECORE_INIT_LOCKS(new_node);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Description: Allocate a new tree node
|
||||
* Parameters: None.
|
||||
* Returns: NULL if the operation fails, otherwise a pointer to the new node.
|
||||
*/
|
||||
Ecore_Tree_Node *ecore_tree_node_new()
|
||||
{
|
||||
Ecore_Tree_Node *new_node;
|
||||
|
||||
new_node = ECORE_TREE_NODE(malloc(sizeof(Ecore_Tree_Node)));
|
||||
if (!new_node)
|
||||
return NULL;
|
||||
|
||||
if (!ecore_tree_node_init(new_node)) {
|
||||
IF_FREE(new_node);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return new_node;
|
||||
}
|
||||
|
||||
/*
|
||||
* Description: Free a tree node and it's children. If you don't want the
|
||||
* children free'd then you need to remove the node first.
|
||||
* Parameters: 1. node - tree node to be free()'d
|
||||
* 2. data_free - callback for destroying the data held in node
|
||||
* Returns: TRUE if the node is destroyed successfully, FALSE if not.
|
||||
*/
|
||||
int ecore_tree_node_destroy(Ecore_Tree_Node * node, Ecore_Free_Cb data_free)
|
||||
{
|
||||
CHECK_PARAM_POINTER_RETURN("node", node, FALSE);
|
||||
|
||||
ECORE_WRITE_LOCK(node);
|
||||
if (data_free)
|
||||
data_free(node->value);
|
||||
ECORE_WRITE_UNLOCK(node);
|
||||
|
||||
ECORE_DESTROY_LOCKS(node);
|
||||
|
||||
FREE(node);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* ecore_tree_node_value_set - set the value of the node to value
|
||||
* @node: the node to be set
|
||||
* @value: the value to set the node to.
|
||||
*
|
||||
* Returns TRUE if the node is set successfully, FALSE if not.
|
||||
*/
|
||||
int ecore_tree_node_value_set(Ecore_Tree_Node * node, void *value)
|
||||
{
|
||||
CHECK_PARAM_POINTER_RETURN("node", node,
|
||||
FALSE);
|
||||
|
||||
ECORE_WRITE_LOCK(node);
|
||||
node->value = value;
|
||||
ECORE_WRITE_UNLOCK(node);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Description: Get the value of the node
|
||||
* Parameters: 1. node - the node that contains the desired value
|
||||
* Returns: NULL if an error, otherwise the value associated with node
|
||||
*/
|
||||
void *ecore_tree_node_value_get(Ecore_Tree_Node * node)
|
||||
{
|
||||
void *ret;
|
||||
|
||||
CHECK_PARAM_POINTER_RETURN("node", node, FALSE);
|
||||
ECORE_READ_LOCK(node);
|
||||
ret = node->value;
|
||||
ECORE_READ_UNLOCK(node);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* ecore_tree_node_key_set - set the value of the node's key to key
|
||||
* @node: the node to be set
|
||||
* @key: the value to set it's key to.
|
||||
*
|
||||
* Returns TRUE if the node is set successfully, FALSE if not.
|
||||
*/
|
||||
int ecore_tree_node_key_set(Ecore_Tree_Node * node, void *key)
|
||||
{
|
||||
CHECK_PARAM_POINTER_RETURN("node", node, FALSE);
|
||||
|
||||
ECORE_WRITE_LOCK(node);
|
||||
node->key = key;
|
||||
ECORE_WRITE_UNLOCK(node);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* ecore_tree_node_key_get - get the value of the node's key
|
||||
* @node: the node that contains the desired key
|
||||
*
|
||||
* Returns NULL if an error occurs, otherwise the key is returned
|
||||
*/
|
||||
void *ecore_tree_node_key_get(Ecore_Tree_Node * node)
|
||||
{
|
||||
void *ret;
|
||||
|
||||
CHECK_PARAM_POINTER_RETURN("node", node, FALSE);
|
||||
ECORE_READ_LOCK(node);
|
||||
ret = node->key;
|
||||
ECORE_READ_UNLOCK(node);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* ecore_tree_destroy - free the tree and it's stored data
|
||||
* @tree: the tree to destroy
|
||||
*
|
||||
* Returns TRUE if tree destroyed successfully, FALSE if not.
|
||||
*/
|
||||
int ecore_tree_destroy(Ecore_Tree * tree)
|
||||
{
|
||||
Ecore_Tree_Node *node;
|
||||
|
||||
CHECK_PARAM_POINTER_RETURN("tree", tree, FALSE);
|
||||
|
||||
ECORE_WRITE_LOCK(tree);
|
||||
while ((node = tree->tree)) {
|
||||
ecore_tree_remove_node(tree, node);
|
||||
ecore_tree_node_destroy(node, tree->free_func);
|
||||
}
|
||||
ECORE_WRITE_UNLOCK(tree);
|
||||
ECORE_DESTROY_LOCKS(tree);
|
||||
|
||||
FREE(tree);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* ecore_tree_get_node - return the node corresponding to key
|
||||
* @tree: the tree to search
|
||||
* @key: the key to search for in the tree
|
||||
*
|
||||
* Returns the node corresponding to the key if found, otherwise NULL.
|
||||
*/
|
||||
Ecore_Tree_Node *ecore_tree_get_node(Ecore_Tree * tree, void *key)
|
||||
{
|
||||
Ecore_Tree_Node *ret;
|
||||
|
||||
CHECK_PARAM_POINTER_RETURN("tree", tree, FALSE);
|
||||
|
||||
ECORE_READ_LOCK(tree);
|
||||
ret = tree_node_find(tree, key);
|
||||
ECORE_READ_UNLOCK(tree);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* ecore_tree_get - return the value corresponding to key
|
||||
* @tree: the tree to search
|
||||
* @key: the key to search for in @tree
|
||||
*
|
||||
* Returns the value corresponding to the key if found, otherwise NULL.
|
||||
*/
|
||||
void *ecore_tree_get(Ecore_Tree * tree, void *key)
|
||||
{
|
||||
void *ret;
|
||||
Ecore_Tree_Node *node;
|
||||
|
||||
CHECK_PARAM_POINTER_RETURN("tree", tree, FALSE);
|
||||
|
||||
ECORE_READ_LOCK(tree);
|
||||
node = tree_node_find(tree, key);
|
||||
ECORE_READ_UNLOCK(tree);
|
||||
|
||||
ECORE_READ_LOCK(node);
|
||||
ret = (node ? node->value : NULL);
|
||||
ECORE_READ_UNLOCK(node);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* ecore_tree_get_closest_larger - find the closest value greater >= key
|
||||
* @tree: the tree to search
|
||||
* @key: the key to search for in @tree
|
||||
*
|
||||
* Returns NULL if no valid nodes, otherwise the node >= key
|
||||
*/
|
||||
void *ecore_tree_get_closest_larger(Ecore_Tree * tree, void *key)
|
||||
{
|
||||
Ecore_Tree_Node *node;
|
||||
|
||||
CHECK_PARAM_POINTER_RETURN("tree", tree, FALSE);
|
||||
|
||||
ECORE_READ_LOCK(tree);
|
||||
node = tree_node_find(tree, key);
|
||||
ECORE_READ_UNLOCK(tree);
|
||||
|
||||
if (node)
|
||||
return node;
|
||||
|
||||
ECORE_READ_LOCK(tree);
|
||||
node = tree_node_find_parent(tree, key);
|
||||
|
||||
if (!node) {
|
||||
ECORE_READ_UNLOCK(tree);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ECORE_READ_LOCK(node);
|
||||
if (tree->compare_func(node->key, key) < 0)
|
||||
return NULL;
|
||||
ECORE_READ_UNLOCK(node);
|
||||
ECORE_READ_UNLOCK(tree);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* ecore_tree_get_closest_smaller - find the closest value <= key
|
||||
* @tree: the tree to search
|
||||
* @key: the key to search for in tree
|
||||
*
|
||||
* Returns NULL if no valid nodes, otherwise the node <= key
|
||||
*/
|
||||
void *ecore_tree_get_closest_smaller(Ecore_Tree * tree, void *key)
|
||||
{
|
||||
Ecore_Tree_Node *node;
|
||||
|
||||
CHECK_PARAM_POINTER_RETURN("tree", tree, FALSE);
|
||||
|
||||
ECORE_READ_LOCK(tree);
|
||||
node = tree_node_find(tree, key);
|
||||
ECORE_READ_UNLOCK(tree);
|
||||
|
||||
if (node)
|
||||
return node;
|
||||
|
||||
ECORE_READ_LOCK(tree);
|
||||
node = tree_node_find_parent(tree, key);
|
||||
ECORE_READ_LOCK(tree);
|
||||
|
||||
if (node)
|
||||
node = node->right_child;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* ecore_tree_set - set the value associated with key to @value
|
||||
* @tree: the tree that contains the key/value pair
|
||||
* @key: the key to identify which node to set a value
|
||||
* @value: value to set the found node
|
||||
*
|
||||
* Returns TRUE if successful, FALSE if not.
|
||||
*/
|
||||
int ecore_tree_set(Ecore_Tree * tree, void *key, void *value)
|
||||
{
|
||||
Ecore_Tree_Node *node = NULL;
|
||||
|
||||
CHECK_PARAM_POINTER_RETURN("tree", tree, FALSE);
|
||||
|
||||
ECORE_READ_LOCK(tree);
|
||||
node = tree_node_find(tree, key);
|
||||
ECORE_READ_UNLOCK(tree);
|
||||
|
||||
if (!node) {
|
||||
node = ecore_tree_node_new();
|
||||
ecore_tree_node_key_set(node, key);
|
||||
if (!ecore_tree_add_node(tree, node))
|
||||
return FALSE;
|
||||
}
|
||||
ecore_tree_node_value_set(node, value);
|
||||
|
||||
ECORE_WRITE_LOCK(tree);
|
||||
for (; node; node = node->parent)
|
||||
tree_node_balance(tree, node);
|
||||
ECORE_WRITE_UNLOCK(tree);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* ecore_tree_add_node - place a node in the tree
|
||||
* @tree: the tree to add @node
|
||||
* @node: the node to add to @tree
|
||||
*
|
||||
* Returns TRUE on a successful add, FALSE otherwise.
|
||||
*/
|
||||
int ecore_tree_add_node(Ecore_Tree * tree, Ecore_Tree_Node * node)
|
||||
{
|
||||
Ecore_Tree_Node *travel = NULL;
|
||||
|
||||
CHECK_PARAM_POINTER_RETURN("tree", tree, FALSE);
|
||||
CHECK_PARAM_POINTER_RETURN("node", node, FALSE);
|
||||
|
||||
/* Find where to put this new node. */
|
||||
if (!tree->tree) {
|
||||
tree->tree = node;
|
||||
} else {
|
||||
travel = tree_node_find_parent(tree, node->key);
|
||||
node->parent = travel;
|
||||
|
||||
/* The node is less than travel */
|
||||
if (tree->compare_func(node->key, travel->key) < 0) {
|
||||
travel->right_child = node;
|
||||
travel->max_left = 1;
|
||||
/* The node is greater than travel */
|
||||
} else {
|
||||
travel->left_child = node;
|
||||
travel->max_right = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ecore_tree_remove_node - remove the node from the tree
|
||||
* @tree: the tree to remove @node
|
||||
* @node: the node to remove from @tree
|
||||
*
|
||||
* Returns TRUE on a successful remove, FALSE otherwise.
|
||||
*/
|
||||
int ecore_tree_remove_node(Ecore_Tree * tree, Ecore_Tree_Node * node)
|
||||
{
|
||||
Ecore_Tree_Node *traverse;
|
||||
|
||||
CHECK_PARAM_POINTER_RETURN("tree", tree, FALSE);
|
||||
CHECK_PARAM_POINTER_RETURN("node", node, FALSE);
|
||||
|
||||
/*
|
||||
* Find the nearest value to the balanced one.
|
||||
*/
|
||||
if (node->left_child) {
|
||||
traverse = node->left_child;
|
||||
|
||||
/* Now work our way down right side of the traverse node.
|
||||
* This will give us the node with the next closest value
|
||||
* to the current node. If traverse had no right node, then
|
||||
* this will stop at node's left node. */
|
||||
while (traverse->right_child) {
|
||||
traverse = traverse->right_child;
|
||||
}
|
||||
|
||||
/*
|
||||
* Hook any dropped leaves into the moved nodes spot
|
||||
*/
|
||||
if (traverse->parent)
|
||||
traverse->parent->left_child = traverse->left_child;
|
||||
}
|
||||
else if (node->right_child) {
|
||||
traverse = node->right_child;
|
||||
|
||||
/* Now work our way down left side of the traverse node.
|
||||
* This will give us the node with the next closest value
|
||||
* to the current node. If traverse had no left node, then
|
||||
* this will stop at node's right node. */
|
||||
while (traverse->left_child) {
|
||||
traverse = traverse->left_child;
|
||||
}
|
||||
|
||||
/*
|
||||
* Hook any dropped leaves into the moved nodes spot
|
||||
*/
|
||||
if (traverse->right_child)
|
||||
traverse->right_child->parent = traverse->parent;
|
||||
|
||||
if (traverse->parent)
|
||||
traverse->parent->right_child = traverse->right_child;
|
||||
else
|
||||
tree->tree = traverse->right_child;
|
||||
}
|
||||
else
|
||||
traverse = NULL;
|
||||
|
||||
if (traverse) {
|
||||
|
||||
/*
|
||||
* Ensure that we don't get a recursive reference.
|
||||
*/
|
||||
if (node->right_child && node->right_child != traverse) {
|
||||
node->right_child->parent = traverse;
|
||||
traverse->right_child = node->right_child;
|
||||
}
|
||||
|
||||
if (node->left_child && node->left_child != traverse) {
|
||||
node->left_child->parent = traverse;
|
||||
traverse->left_child = node->left_child;
|
||||
}
|
||||
|
||||
/*
|
||||
* Unlink the node to be moved from it's parent.
|
||||
*/
|
||||
if (traverse->parent) {
|
||||
if (traverse->parent->left_child == traverse)
|
||||
traverse->parent->left_child = NULL;
|
||||
else
|
||||
traverse->parent->right_child = NULL;
|
||||
}
|
||||
traverse->parent = node->parent;
|
||||
}
|
||||
|
||||
if (node->parent) {
|
||||
if (node == node->parent->left_child)
|
||||
node->parent->left_child = traverse;
|
||||
else
|
||||
node->parent->right_child = traverse;
|
||||
}
|
||||
|
||||
if (tree->tree == node)
|
||||
tree->tree = traverse;
|
||||
|
||||
node->parent = node->left_child = node->right_child = NULL;
|
||||
|
||||
/*
|
||||
* Rebalance the tree to ensure short search paths.
|
||||
*/
|
||||
while (traverse) {
|
||||
tree_node_balance(tree, traverse);
|
||||
traverse = traverse->parent;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* ecore_tree_remove - remove the key from the tree
|
||||
* @tree: the tree to remove @key
|
||||
* @key: the key to remove from @tree
|
||||
*
|
||||
* Returns TRUE on a successful remove, FALSE otherwise.
|
||||
*/
|
||||
int ecore_tree_remove(Ecore_Tree * tree, void *key)
|
||||
{
|
||||
Ecore_Tree_Node *node;
|
||||
|
||||
CHECK_PARAM_POINTER_RETURN("tree", tree, FALSE);
|
||||
if (!tree->tree)
|
||||
return FALSE;
|
||||
|
||||
/* Find the node we need to remove */
|
||||
node = tree_node_find(tree, key);
|
||||
if (!node)
|
||||
return FALSE;
|
||||
|
||||
if (!ecore_tree_remove_node(tree, node))
|
||||
return FALSE;
|
||||
|
||||
ecore_tree_node_destroy(node, tree->free_func);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* ecore_tree_is_empty - test to see if the tree has any nodes
|
||||
* @tree: the tree to check for nodes
|
||||
*
|
||||
* Returns TRUE if no nodes exist, FALSE otherwise
|
||||
*/
|
||||
int ecore_tree_is_empty(Ecore_Tree * tree)
|
||||
{
|
||||
CHECK_PARAM_POINTER_RETURN("tree", tree, FALSE);
|
||||
|
||||
if (!tree->tree)
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* ecore_tree_for_each_node_value - execute function for each value in the tree
|
||||
* @tree: the tree to traverse
|
||||
* @for_each_func: the function to execute for each value in the tree
|
||||
*
|
||||
* Returns TRUE on success, FALSE on failure.
|
||||
*/
|
||||
int ecore_tree_for_each_node_value(Ecore_Tree * tree,
|
||||
Ecore_For_Each for_each_func)
|
||||
{
|
||||
CHECK_PARAM_POINTER_RETURN("tree", tree, FALSE);
|
||||
CHECK_PARAM_POINTER_RETURN("for_each_func", for_each_func, FALSE);
|
||||
|
||||
if (!tree->tree)
|
||||
return FALSE;
|
||||
|
||||
return tree_for_each_node_value(tree->tree, for_each_func);
|
||||
}
|
||||
|
||||
/**
|
||||
* ecore_tree_for_each_node - execute the function for each node in the tree
|
||||
* @tree: the tree to traverse
|
||||
* @for_each_func: the function to execute for each node
|
||||
*
|
||||
* Returns TRUE on success, FALSE on failure.
|
||||
*/
|
||||
int ecore_tree_for_each_node(Ecore_Tree * tree, Ecore_For_Each for_each_func)
|
||||
{
|
||||
CHECK_PARAM_POINTER_RETURN("tree", tree, FALSE);
|
||||
CHECK_PARAM_POINTER_RETURN("for_each_func", for_each_func, FALSE);
|
||||
|
||||
if (!tree->tree)
|
||||
return FALSE;
|
||||
|
||||
return tree_for_each_node(tree->tree, for_each_func);
|
||||
}
|
||||
|
||||
/* Find the parent for the key */
|
||||
Ecore_Tree_Node *tree_node_find_parent(Ecore_Tree * tree, void *key)
|
||||
{
|
||||
Ecore_Tree_Node *parent, *travel;
|
||||
|
||||
CHECK_PARAM_POINTER_RETURN("tree", tree, FALSE);
|
||||
|
||||
parent = tree_node_find(tree, key);
|
||||
if (parent)
|
||||
parent = parent->parent;
|
||||
|
||||
travel = tree->tree;
|
||||
if (!travel)
|
||||
return NULL;
|
||||
|
||||
while (!parent) {
|
||||
int compare;
|
||||
|
||||
if ((compare = tree->compare_func(key, travel->key)) < 0) {
|
||||
if (!travel->right_child)
|
||||
parent = travel;
|
||||
travel = travel->right_child;
|
||||
} else {
|
||||
if (!travel->left_child)
|
||||
parent = travel;
|
||||
travel = travel->left_child;
|
||||
}
|
||||
}
|
||||
|
||||
return parent;
|
||||
}
|
||||
|
||||
/* Search for the node with a specified key */
|
||||
Ecore_Tree_Node *tree_node_find(Ecore_Tree * tree, void *key)
|
||||
{
|
||||
int compare;
|
||||
Ecore_Tree_Node *node;
|
||||
|
||||
CHECK_PARAM_POINTER_RETURN("tree", tree, FALSE);
|
||||
|
||||
node = tree->tree;
|
||||
while (node && (compare = tree->compare_func(key, node->key)) != 0) {
|
||||
|
||||
if (compare < 0) {
|
||||
if (!node->right_child) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
node = node->right_child;
|
||||
} else {
|
||||
if (!node->left_child) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
node = node->left_child;
|
||||
}
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
/* Balance the tree with respect to node */
|
||||
int tree_node_balance(Ecore_Tree * tree, Ecore_Tree_Node * top_node)
|
||||
{
|
||||
int balance;
|
||||
|
||||
CHECK_PARAM_POINTER_RETURN("top_node", top_node, FALSE);
|
||||
|
||||
/* Get the height of the left branch. */
|
||||
if (top_node->right_child) {
|
||||
top_node->max_left = MAX_HEIGHT(top_node->right_child) + 1;
|
||||
} else
|
||||
top_node->max_left = 0;
|
||||
|
||||
/* Get the height of the right branch. */
|
||||
if (top_node->left_child) {
|
||||
top_node->max_right = MAX_HEIGHT(top_node->left_child) + 1;
|
||||
} else
|
||||
top_node->max_right = 0;
|
||||
|
||||
/* Determine which side has a larger height. */
|
||||
balance = top_node->max_right - top_node->max_left;
|
||||
|
||||
/* if the left side has a height advantage >1 rotate right */
|
||||
if (balance < -1)
|
||||
tree_node_rotate_right(tree, top_node);
|
||||
/* else if the left side has a height advantage >1 rotate left */
|
||||
else if (balance > 1)
|
||||
tree_node_rotate_left(tree, top_node);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Tree is overbalanced to the left, so rotate nodes to the right. */
|
||||
int tree_node_rotate_right(Ecore_Tree * tree, Ecore_Tree_Node * top_node)
|
||||
{
|
||||
Ecore_Tree_Node *temp;
|
||||
|
||||
CHECK_PARAM_POINTER_RETURN("top_node", top_node, FALSE);
|
||||
|
||||
/* The left branch's right branch becomes the nodes left branch,
|
||||
* the left branch becomes the top node, and the node becomes the
|
||||
* right branch. */
|
||||
temp = top_node->right_child;
|
||||
top_node->right_child = temp->left_child;
|
||||
temp->left_child = top_node;
|
||||
|
||||
/* Make sure the nodes know who their new parents are and the tree
|
||||
* structure knows the start of the tree. */
|
||||
temp->parent = top_node->parent;
|
||||
if (temp->parent == NULL)
|
||||
tree->tree = temp;
|
||||
else {
|
||||
if (temp->parent->left_child == top_node)
|
||||
temp->parent->left_child = temp;
|
||||
else
|
||||
temp->parent->right_child = temp;
|
||||
}
|
||||
top_node->parent = temp;
|
||||
|
||||
/* And recalculate node heights */
|
||||
tree_node_balance(tree, top_node);
|
||||
tree_node_balance(tree, temp);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* The tree is overbalanced to the right, so we rotate nodes to the left */
|
||||
int tree_node_rotate_left(Ecore_Tree * tree, Ecore_Tree_Node * top_node)
|
||||
{
|
||||
Ecore_Tree_Node *temp;
|
||||
|
||||
CHECK_PARAM_POINTER_RETURN("top_node", top_node, FALSE);
|
||||
|
||||
/*
|
||||
* The right branch's left branch becomes the nodes right branch,
|
||||
* the right branch becomes the top node, and the node becomes the
|
||||
* left branch.
|
||||
*/
|
||||
temp = top_node->left_child;
|
||||
top_node->left_child = temp->right_child;
|
||||
temp->right_child = top_node;
|
||||
|
||||
/* Make sure the nodes know who their new parents are. */
|
||||
temp->parent = top_node->parent;
|
||||
if (temp->parent == NULL)
|
||||
tree->tree = temp;
|
||||
else {
|
||||
if (temp->parent->left_child == top_node)
|
||||
temp->parent->left_child = temp;
|
||||
else
|
||||
temp->parent->right_child = temp;
|
||||
}
|
||||
top_node->parent = temp;
|
||||
|
||||
/* And recalculate node heights */
|
||||
tree_node_balance(tree, top_node);
|
||||
tree_node_balance(tree, temp);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Description: Execute a function for each node below this point in the tree.
|
||||
* Parameters: 1. node - the highest node in the tree the function will be
|
||||
* executed for
|
||||
* 2. for_each_func - the function to pass the nodes as data into
|
||||
* Returns: FALSE if an error condition occurs, otherwise TRUE
|
||||
*/
|
||||
int tree_for_each_node(Ecore_Tree_Node * node, Ecore_For_Each for_each_func)
|
||||
{
|
||||
CHECK_PARAM_POINTER_RETURN("node", node, FALSE);
|
||||
|
||||
if (node->right_child)
|
||||
tree_for_each_node(node->right_child, for_each_func);
|
||||
|
||||
if (node->left_child)
|
||||
tree_for_each_node(node->left_child, for_each_func);
|
||||
|
||||
for_each_func(node);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Description: Execute a function for each node below this point in the tree.
|
||||
* Parameters: 1. node - the highest node in the tree the function will be
|
||||
* executed for
|
||||
* 2. for_each_func - the function to pass the nodes values as data
|
||||
* Returns: FALSE if an error condition occurs, otherwise TRUE
|
||||
*/
|
||||
int tree_for_each_node_value(Ecore_Tree_Node * node,
|
||||
Ecore_For_Each for_each_func)
|
||||
{
|
||||
CHECK_PARAM_POINTER_RETURN("node", node, FALSE);
|
||||
|
||||
if (node->right_child)
|
||||
tree_for_each_node_value(node->right_child, for_each_func);
|
||||
|
||||
if (node->left_child)
|
||||
tree_for_each_node_value(node->left_child, for_each_func);
|
||||
|
||||
for_each_func(node->value);
|
||||
|
||||
return TRUE;
|
||||
}
|
|
@ -0,0 +1,122 @@
|
|||
/* ecore_value.c
|
||||
|
||||
Copyright (C) 2001 Christopher Rosendahl <smugg@fatelabs.com>
|
||||
Nathan Ingersoll <ningerso@d.umn.edu>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to
|
||||
deal in the Software without restriction, including without limitation the
|
||||
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
sell copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies of the Software and its documentation and acknowledgment shall be
|
||||
given in the documentation and software packages that this Software was
|
||||
used.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#include <Ecore.h>
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
inline void ecore_print_warning(char *function, char *sparam)
|
||||
{
|
||||
fprintf(stderr, "***** 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.\n", function, sparam);
|
||||
fflush(stderr);
|
||||
}
|
||||
|
||||
/**
|
||||
* ecore_direct_hash - just casts the key to an unsigned int
|
||||
* @key: the key to return compute a hash value
|
||||
*
|
||||
* Returns the key cast to an unsigned int.
|
||||
*/
|
||||
unsigned int ecore_direct_hash(void *key)
|
||||
{
|
||||
return ((unsigned int) key);
|
||||
}
|
||||
|
||||
/**
|
||||
* ecore_str_hash - compute the hash value of a string
|
||||
* @key: a pointer to the string to compute a hash value
|
||||
*
|
||||
* Returns a computed hash value for @key.
|
||||
*/
|
||||
unsigned int ecore_str_hash(void *key)
|
||||
{
|
||||
int i;
|
||||
unsigned int value = 0;
|
||||
char *k = (char *) key;
|
||||
|
||||
if (!k)
|
||||
return 0;
|
||||
|
||||
for (i = 0; k[i] != '\0'; i++) {
|
||||
value ^= ((unsigned int) k[i] << ((i * 5) %
|
||||
(sizeof(unsigned int) * 8)));
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* ecore_direct_compare - perform a direct comparison of two keys values
|
||||
* @key1: the first key to compare
|
||||
* @key2: the second key to compare
|
||||
*
|
||||
* Return a strcmp style value to indicate the larger key
|
||||
*/
|
||||
int ecore_direct_compare(void *key1, void *key2)
|
||||
{
|
||||
unsigned int k1, k2;
|
||||
|
||||
k1 = (unsigned int) key1;
|
||||
k2 = (unsigned int) key2;
|
||||
|
||||
if (k1 > k2)
|
||||
return 1;
|
||||
|
||||
if (k1 < k2)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ecore_direct_compare - perform a string comparison of two keys values
|
||||
* @key1: the first key to compare
|
||||
* @key2: the second key to compare
|
||||
*
|
||||
* Return a strcmp style value to indicate the larger key
|
||||
*/
|
||||
int ecore_str_compare(void *key1, void *key2)
|
||||
{
|
||||
char *k1, *k2;
|
||||
|
||||
if (!key1 || !key2)
|
||||
return ecore_direct_compare(key1, key2);
|
||||
else if (key1 == key2)
|
||||
return 0;
|
||||
|
||||
k1 = (char *) key1;
|
||||
k2 = (char *) key2;
|
||||
|
||||
return strcmp(k1, k2);
|
||||
}
|
Loading…
Reference in New Issue