forked from enlightenment/efl
eina: in fact this is gone and won't come back.
Eo and Efl.Model are here for that task.
This commit is contained in:
parent
c086d505a9
commit
32d614639f
|
@ -89,10 +89,6 @@ lib/eina/eina_thread_queue.h \
|
|||
lib/eina/eina_matrix.h \
|
||||
lib/eina/eina_quad.h
|
||||
|
||||
# Will be back for developper after 1.2.
|
||||
# lib/eina/eina_model.h
|
||||
# lib/eina/eina_object.h
|
||||
|
||||
lib_eina_libeina_la_SOURCES = \
|
||||
lib/eina/eina_abi.c \
|
||||
lib/eina/eina_accessor.c \
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,852 +0,0 @@
|
|||
/* EINA - EFL data type library
|
||||
* Copyright (C) 2011 Cedric Bail
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library;
|
||||
* if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "eina_private.h"
|
||||
#include "eina_inlist.h"
|
||||
#include "eina_rbtree.h"
|
||||
#include "eina_mempool.h"
|
||||
#include "eina_trash.h"
|
||||
#include "eina_log.h"
|
||||
#include "eina_stringshare.h"
|
||||
#include "eina_lock.h"
|
||||
|
||||
#include "eina_object.h"
|
||||
|
||||
/*============================================================================*
|
||||
* Local *
|
||||
*============================================================================*/
|
||||
|
||||
/**
|
||||
* @cond LOCAL
|
||||
*/
|
||||
|
||||
/* If we are on a 64bits computer user bigger generation and ID */
|
||||
/* FIXME: make it GCC independent */
|
||||
/* FIXME: maybe having 2^32 objects doesn't make sense and 2^24 are enough
|
||||
so instead of increasing the object count, we could just add a magic
|
||||
to first check if the pointer is valid at all (and maybe use a pointer
|
||||
that will always trigger a segv if we try to use it directly).
|
||||
*/
|
||||
#ifdef _LP64
|
||||
typedef unsigned long Eina_Object_ID;
|
||||
typedef unsigned short Eina_Object_Generation;
|
||||
# define EINA_GEN_OFFSET 48
|
||||
# define EINA_ID_STR "%lu"
|
||||
#elif _WIN64
|
||||
typedef unsigned __int64 Eina_Object_ID;
|
||||
typedef unsigned short Eina_Object_Generation;
|
||||
# define EINA_GEN_OFFSET 48
|
||||
# define EINA_ID_STR "%I64u"
|
||||
#else
|
||||
typedef unsigned int Eina_Object_ID;
|
||||
typedef unsigned char Eina_Object_Generation;
|
||||
# define EINA_GEN_OFFSET 24
|
||||
# define EINA_ID_STR "%u"
|
||||
#endif
|
||||
|
||||
typedef struct _Eina_Class_Range Eina_Class_Range;
|
||||
typedef struct _Eina_Object_Item Eina_Object_Item;
|
||||
typedef struct _Eina_Range Eina_Range;
|
||||
typedef struct _Eina_Class_Top Eina_Class_Top;
|
||||
|
||||
struct _Eina_Range
|
||||
{
|
||||
EINA_INLIST;
|
||||
|
||||
unsigned int start;
|
||||
unsigned int end;
|
||||
};
|
||||
|
||||
struct _Eina_Object_Item
|
||||
{
|
||||
EINA_INLIST;
|
||||
Eina_Class_Range *range;
|
||||
|
||||
Eina_Object_Item *parent;
|
||||
Eina_Inlist *link;
|
||||
|
||||
unsigned int index;
|
||||
};
|
||||
|
||||
struct _Eina_Class_Range
|
||||
{
|
||||
EINA_INLIST;
|
||||
EINA_RBTREE;
|
||||
|
||||
unsigned int start;
|
||||
unsigned int end;
|
||||
unsigned int current;
|
||||
unsigned int empty_count;
|
||||
|
||||
Eina_Class *type;
|
||||
Eina_Trash *empty;
|
||||
|
||||
Eina_Object_Item **pointer_array;
|
||||
Eina_Object_Generation generation_array[1];
|
||||
};
|
||||
|
||||
struct _Eina_Class_Top
|
||||
{
|
||||
Eina_Class *top_parent;
|
||||
Eina_Rbtree *range;
|
||||
Eina_Inlist *available;
|
||||
|
||||
unsigned int upper_limit;
|
||||
};
|
||||
|
||||
struct _Eina_Class
|
||||
{
|
||||
EINA_INLIST;
|
||||
|
||||
const char *name;
|
||||
|
||||
Eina_Class_Top *top;
|
||||
|
||||
Eina_Class *parent;
|
||||
Eina_Inlist *childs;
|
||||
|
||||
Eina_Class_Callback constructor;
|
||||
Eina_Class_Callback destructor;
|
||||
void *data;
|
||||
|
||||
Eina_Inlist *allocated_range;
|
||||
|
||||
Eina_Mempool *mempool;
|
||||
unsigned int class_size;
|
||||
unsigned int object_size;
|
||||
unsigned int pool_size;
|
||||
|
||||
Eina_Bool repack_needed : 1;
|
||||
|
||||
#ifdef EINA_HAVE_DEBUG_THREADS
|
||||
pthread_t self;
|
||||
#endif
|
||||
Eina_Lock mutex;
|
||||
|
||||
EINA_MAGIC;
|
||||
};
|
||||
|
||||
static const char EINA_MAGIC_CLASS_STR[] = "Eina Class";
|
||||
|
||||
static Eina_Mempool *_eina_class_mp = NULL;
|
||||
static Eina_Mempool *_eina_top_mp = NULL;
|
||||
static Eina_Mempool *_eina_range_mp = NULL;
|
||||
static int _eina_object_log_dom = -1;
|
||||
static unsigned int _eina_object_item_size = 0;
|
||||
|
||||
#ifdef ERR
|
||||
#undef ERR
|
||||
#endif
|
||||
#define ERR(...) EINA_LOG_DOM_ERR(_eina_object_log_dom, __VA_ARGS__)
|
||||
|
||||
#ifdef DBG
|
||||
#undef DBG
|
||||
#endif
|
||||
#define DBG(...) EINA_LOG_DOM_DBG(_eina_object_log_dom, __VA_ARGS__)
|
||||
|
||||
#define EINA_MAGIC_CHECK_CLASS(d, ...) \
|
||||
do { \
|
||||
if (!EINA_MAGIC_CHECK(d, EINA_MAGIC_CLASS)) \
|
||||
{ \
|
||||
EINA_MAGIC_FAIL(d, EINA_MAGIC_CLASS); \
|
||||
return __VA_ARGS__; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
static int
|
||||
_eina_rbtree_cmp_range(const Eina_Rbtree *node, const void *key,
|
||||
EINA_UNUSED int length, EINA_UNUSED void *data)
|
||||
{
|
||||
Eina_Class_Range *range;
|
||||
Eina_Object_ID id;
|
||||
|
||||
range = EINA_RBTREE_CONTAINER_GET(node, Eina_Class_Range);
|
||||
id = (Eina_Object_ID) key;
|
||||
|
||||
if (id < range->start) return -1;
|
||||
else if (id >= range->end) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static Eina_Rbtree_Direction
|
||||
_eina_class_direction_range(const Eina_Rbtree *left,
|
||||
const Eina_Rbtree *right,
|
||||
EINA_UNUSED void *data)
|
||||
{
|
||||
Eina_Class_Range *rl;
|
||||
Eina_Class_Range *rr;
|
||||
|
||||
rl = EINA_RBTREE_CONTAINER_GET(left, Eina_Class_Range);
|
||||
rr = EINA_RBTREE_CONTAINER_GET(right, Eina_Class_Range);
|
||||
|
||||
if (rl->start < rr->start) return EINA_RBTREE_LEFT;
|
||||
return EINA_RBTREE_RIGHT;
|
||||
}
|
||||
|
||||
/* really destroying a range and handling that case is a complex
|
||||
problem to solve. Not handling it right now, exposing myself to
|
||||
DoS. */
|
||||
static void
|
||||
_eina_range_cleanup(Eina_Class_Range *range)
|
||||
{
|
||||
range->current = 0;
|
||||
range->empty = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
_eina_object_constructor_call(Eina_Class *class, void *object)
|
||||
{
|
||||
if (class->parent) _eina_object_constructor_call(class->parent, object);
|
||||
|
||||
if (class->constructor) class->constructor(class, object, class->data);
|
||||
}
|
||||
|
||||
static void
|
||||
_eina_object_destructor_call(Eina_Class *class, void *object)
|
||||
{
|
||||
if (class->destructor) class->destructor(class, object, class->data);
|
||||
|
||||
if (class->parent) _eina_object_destructor_call(class->parent, object);
|
||||
}
|
||||
|
||||
static Eina_Object*
|
||||
_eina_object_get(Eina_Object_Item *item)
|
||||
{
|
||||
Eina_Object_Generation gen;
|
||||
Eina_Object_ID id;
|
||||
|
||||
if (!item) return NULL;
|
||||
|
||||
gen = item->range->generation_array[item->index];
|
||||
|
||||
id = ((Eina_Object_ID) gen << EINA_GEN_OFFSET) + item->range->start + item->index;
|
||||
|
||||
return (Eina_Object *) id;
|
||||
}
|
||||
|
||||
static Eina_Object_Item *
|
||||
_eina_object_find_item(Eina_Class *class, Eina_Object *object)
|
||||
{
|
||||
Eina_Class_Range *matched;
|
||||
Eina_Object_Item *item;
|
||||
Eina_Class *search;
|
||||
Eina_Rbtree *match;
|
||||
Eina_Object_Generation generation;
|
||||
Eina_Object_ID id;
|
||||
Eina_Object_ID idx;
|
||||
|
||||
id = (Eina_Object_ID) object;
|
||||
idx = id & (((Eina_Object_ID) 1 << EINA_GEN_OFFSET) - 1);
|
||||
generation = id & !(((Eina_Object_ID) 1 << EINA_GEN_OFFSET) - 1);
|
||||
|
||||
/* Try to find the ID */
|
||||
match = eina_rbtree_inline_lookup(class->top->range,
|
||||
(void*) idx, sizeof (Eina_Object_ID),
|
||||
_eina_rbtree_cmp_range, NULL);
|
||||
/* ID not found, invalid pointer ! */
|
||||
if (!match)
|
||||
{
|
||||
ERR("%p: ID ["EINA_ID_STR"] not found in class hiearchy of [%s].",
|
||||
object, idx, class->name);
|
||||
return NULL;
|
||||
}
|
||||
matched = EINA_RBTREE_CONTAINER_GET(match, Eina_Class_Range);
|
||||
|
||||
/* generation mismatch, invalid pointer ! */
|
||||
if (generation != matched->generation_array[idx - matched->start])
|
||||
{
|
||||
ERR("%p: generation mismatch [%i] vs [%i].",
|
||||
object, generation, matched->generation_array[idx - matched->start]);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* does it belong to the right class ? */
|
||||
for (search = matched->type; search && search != class; search = search->parent)
|
||||
;
|
||||
|
||||
/* class match request or invalid pointer ! */
|
||||
if (search != class)
|
||||
{
|
||||
ERR("%p: from class [%s] is not in the hierarchie of [%s].",
|
||||
object, matched->type->name, class->name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* retrieve pointer */
|
||||
item = matched->pointer_array[id - matched->start];
|
||||
/* allocated or invalid pointer ? */
|
||||
if (!item)
|
||||
{
|
||||
ERR("%p: ID is not allocated.", object);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* be aware, that because we use eina_trash to store empty pointer after first use,
|
||||
pointer could be != NULL and still be empty. Need another pool of data somewhere
|
||||
to store the state of the allocation... Is it needed ?
|
||||
*/
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
static void
|
||||
_eina_object_item_del(Eina_Object_Item *item)
|
||||
{
|
||||
Eina_Class *class;
|
||||
|
||||
class = item->range->type;
|
||||
_eina_object_destructor_call(class,
|
||||
(unsigned char*) item + _eina_object_item_size);
|
||||
|
||||
eina_trash_push(&item->range->empty, item->range->pointer_array + item->index);
|
||||
item->range->generation_array[item->index]++;
|
||||
item->range->empty_count++;
|
||||
|
||||
if (item->range->empty_count == item->range->end - item->range->start)
|
||||
_eina_range_cleanup(item->range);
|
||||
item->range = NULL;
|
||||
|
||||
if (item->parent)
|
||||
item->parent->link = eina_inlist_remove(item->parent->link, EINA_INLIST_GET(item));
|
||||
item->parent = NULL;
|
||||
|
||||
while (item->link)
|
||||
{
|
||||
Eina_Object_Item *child;
|
||||
|
||||
child = EINA_INLIST_CONTAINER_GET(item->link, Eina_Object_Item);
|
||||
_eina_object_item_del(child);
|
||||
}
|
||||
|
||||
eina_mempool_free(class->mempool, item);
|
||||
}
|
||||
|
||||
static Eina_Class_Range *
|
||||
_eina_class_empty_range_get(Eina_Inlist *list)
|
||||
{
|
||||
while (list)
|
||||
{
|
||||
Eina_Class_Range *range;
|
||||
|
||||
range = EINA_INLIST_CONTAINER_GET(list, Eina_Class_Range);
|
||||
if (range->empty_count > 0)
|
||||
return range;
|
||||
|
||||
list = list->next;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static Eina_Class_Range *
|
||||
_eina_class_range_add(Eina_Class *class)
|
||||
{
|
||||
Eina_Class_Range *range;
|
||||
unsigned char *tmp;
|
||||
Eina_Range *av = NULL;
|
||||
|
||||
range = malloc(sizeof (Eina_Class_Range)
|
||||
+ sizeof (Eina_Object_Item*) * class->pool_size
|
||||
+ sizeof (Eina_Object_Generation) * (class->pool_size - 1));
|
||||
if (!range) return NULL;
|
||||
|
||||
tmp = (void*) (range + 1);
|
||||
tmp += sizeof (Eina_Object_Generation) * (class->pool_size - 1);
|
||||
|
||||
range->pointer_array = (Eina_Object_Item**) tmp;
|
||||
|
||||
/* no need to fix generation to a specific value as random value should be just fine */
|
||||
memset(range->pointer_array, 0, sizeof (Eina_Object_Item*) * class->pool_size);
|
||||
|
||||
range->current = 0;
|
||||
range->type = class;
|
||||
range->empty = NULL;
|
||||
|
||||
/* and now find an empty block */
|
||||
EINA_INLIST_FOREACH(class->top->available, av)
|
||||
if ((av->end - av->start) == class->pool_size)
|
||||
break;
|
||||
|
||||
if (av)
|
||||
{
|
||||
range->start = av->start;
|
||||
range->end = av->end;
|
||||
|
||||
class->top->available = eina_inlist_remove(class->top->available,
|
||||
EINA_INLIST_GET(av));
|
||||
eina_mempool_free(_eina_range_mp, av);
|
||||
}
|
||||
else
|
||||
{
|
||||
range->start = class->top->upper_limit;
|
||||
range->end = range->start + class->pool_size;
|
||||
class->top->upper_limit = range->end;
|
||||
}
|
||||
|
||||
return range;
|
||||
}
|
||||
|
||||
static void
|
||||
_eina_class_range_del(Eina_Class_Range *range)
|
||||
{
|
||||
Eina_Class_Top *top;
|
||||
Eina_Range *keep;
|
||||
|
||||
top = range->type->top;
|
||||
|
||||
keep = eina_mempool_malloc(_eina_range_mp, sizeof (Eina_Range));
|
||||
if (!keep)
|
||||
{
|
||||
ERR("Not enougth memory to keep track of allocated range.");
|
||||
goto delete_class_range;
|
||||
}
|
||||
|
||||
keep->start = range->start;
|
||||
keep->end = range->end;
|
||||
|
||||
top->available = eina_inlist_prepend(top->available,
|
||||
EINA_INLIST_GET(keep));
|
||||
|
||||
delete_class_range:
|
||||
top->range = eina_rbtree_inline_remove(top->range, EINA_RBTREE_GET(range),
|
||||
_eina_class_direction_range, NULL);
|
||||
range->type->allocated_range = eina_inlist_remove(range->type->allocated_range,
|
||||
EINA_INLIST_GET(range));
|
||||
free(range);
|
||||
}
|
||||
|
||||
static void
|
||||
_eina_class_range_repack(void *dst, void *src, void *data)
|
||||
{
|
||||
Eina_Object_Item *di = dst;
|
||||
Eina_Object_Item *si = src;
|
||||
Eina_Class *class = data;
|
||||
|
||||
(void) class;
|
||||
|
||||
si->range->pointer_array[si->index] = di;
|
||||
|
||||
/* FIXME: We could just lock the right Eina_Class_Range
|
||||
here instead of locking all the Class */
|
||||
}
|
||||
|
||||
/**
|
||||
* @endcond
|
||||
*/
|
||||
|
||||
Eina_Bool
|
||||
eina_object_init(void)
|
||||
{
|
||||
_eina_object_log_dom = eina_log_domain_register("eina_object",
|
||||
EINA_LOG_COLOR_DEFAULT);
|
||||
if (_eina_object_log_dom < 0)
|
||||
{
|
||||
EINA_LOG_ERR("Could not register log domain: eina_list");
|
||||
return EINA_FALSE;
|
||||
}
|
||||
|
||||
_eina_class_mp = eina_mempool_add("chained_mempool", "class",
|
||||
NULL, sizeof (Eina_Class), 16);
|
||||
if (!_eina_class_mp)
|
||||
{
|
||||
ERR("ERROR: Mempool for Eina_Class cannot be allocated in object init.");
|
||||
goto on_init_fail;
|
||||
}
|
||||
|
||||
_eina_top_mp = eina_mempool_add("chained_mempool", "top",
|
||||
NULL, sizeof (Eina_Class_Top), 16);
|
||||
if (!_eina_top_mp)
|
||||
{
|
||||
ERR("ERROR: Mempool for Eina_Class_Top cannot be allocated in object init.");
|
||||
goto on_init_fail;
|
||||
}
|
||||
|
||||
_eina_range_mp = eina_mempool_add("chained_mempool", "range",
|
||||
NULL, sizeof (Eina_Range), 16);
|
||||
if (!_eina_range_mp)
|
||||
{
|
||||
ERR("ERROR: Mempool for Eina_Class_Top cannot be allocated in object init.");
|
||||
goto on_init_fail;
|
||||
}
|
||||
|
||||
#define EMS(n) eina_magic_string_static_set(n, n ## _STR)
|
||||
EMS(EINA_MAGIC_CLASS);
|
||||
#undef EMS
|
||||
|
||||
_eina_object_item_size = eina_mempool_alignof(sizeof (Eina_Object_Item));
|
||||
|
||||
return EINA_TRUE;
|
||||
|
||||
on_init_fail:
|
||||
eina_log_domain_unregister(_eina_object_log_dom);
|
||||
_eina_object_log_dom = -1;
|
||||
|
||||
if (_eina_top_mp)
|
||||
{
|
||||
eina_mempool_del(_eina_top_mp);
|
||||
_eina_top_mp = NULL;
|
||||
}
|
||||
|
||||
if (_eina_class_mp)
|
||||
{
|
||||
eina_mempool_del(_eina_class_mp);
|
||||
_eina_class_mp = NULL;
|
||||
}
|
||||
|
||||
return EINA_FALSE;
|
||||
}
|
||||
|
||||
Eina_Bool
|
||||
eina_object_shutdown(void)
|
||||
{
|
||||
eina_mempool_del(_eina_class_mp);
|
||||
eina_mempool_del(_eina_top_mp);
|
||||
|
||||
eina_log_domain_unregister(_eina_object_log_dom);
|
||||
_eina_object_log_dom = -1;
|
||||
return EINA_TRUE;
|
||||
}
|
||||
|
||||
Eina_Class *
|
||||
eina_class_new(const char *name,
|
||||
unsigned int class_size,
|
||||
unsigned int pool_size,
|
||||
Eina_Class_Callback constructor,
|
||||
Eina_Class_Callback destructor,
|
||||
Eina_Class *parent,
|
||||
void *data)
|
||||
{
|
||||
Eina_Class *c;
|
||||
unsigned int object_size = class_size;
|
||||
|
||||
if (parent) EINA_MAGIC_CHECK_CLASS(parent, NULL);
|
||||
|
||||
c = eina_mempool_malloc(_eina_class_mp, sizeof (Eina_Class));
|
||||
if (!c) return NULL;
|
||||
|
||||
c->parent = parent;
|
||||
if (parent)
|
||||
{
|
||||
parent->childs = eina_inlist_append(parent->childs,
|
||||
EINA_INLIST_GET(c));
|
||||
c->top = parent->top;
|
||||
}
|
||||
else
|
||||
{
|
||||
c->top = eina_mempool_malloc(_eina_top_mp, sizeof (Eina_Class_Top));
|
||||
|
||||
c->top->top_parent = c;
|
||||
c->top->range = NULL;
|
||||
c->top->available = NULL;
|
||||
c->top->upper_limit = 0;
|
||||
}
|
||||
|
||||
/* Build complete object size and find top parent */
|
||||
if (parent) object_size += parent->object_size;
|
||||
|
||||
c->name = eina_stringshare_add(name);
|
||||
c->class_size = class_size;
|
||||
c->pool_size = pool_size;
|
||||
c->object_size = object_size;
|
||||
c->mempool = eina_mempool_add("chained_mempool", "range",
|
||||
NULL,
|
||||
_eina_object_item_size + object_size, pool_size);
|
||||
|
||||
c->constructor = constructor;
|
||||
c->destructor = destructor;
|
||||
c->data = data;
|
||||
|
||||
c->allocated_range = NULL;
|
||||
c->childs = NULL;
|
||||
|
||||
#ifdef EINA_HAVE_DEBUG_THREADS
|
||||
c->self = pthread_self();
|
||||
#endif
|
||||
eina_lock_new(&c->mutex);
|
||||
|
||||
EINA_MAGIC_SET(c, EINA_MAGIC_CLASS);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
const char *
|
||||
eina_class_name_get(Eina_Class *class)
|
||||
{
|
||||
EINA_MAGIC_CHECK_CLASS(class, NULL);
|
||||
|
||||
return class->name;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
eina_class_size_get(Eina_Class *class)
|
||||
{
|
||||
EINA_MAGIC_CHECK_CLASS(class, 0);
|
||||
|
||||
return class->class_size;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
eina_class_object_size_get(Eina_Class *class)
|
||||
{
|
||||
EINA_MAGIC_CHECK_CLASS(class, 0);
|
||||
|
||||
return class->object_size;
|
||||
}
|
||||
|
||||
void
|
||||
eina_class_del(Eina_Class *class)
|
||||
{
|
||||
EINA_MAGIC_CHECK_CLASS(class);
|
||||
|
||||
EINA_MAGIC_SET(class, 0);
|
||||
|
||||
while (class->allocated_range)
|
||||
_eina_class_range_del(EINA_INLIST_CONTAINER_GET(class->allocated_range,
|
||||
Eina_Class_Range));
|
||||
|
||||
while (class->childs)
|
||||
{
|
||||
Eina_Class *child;
|
||||
|
||||
child = EINA_INLIST_CONTAINER_GET(class->childs, Eina_Class);
|
||||
eina_class_del(child);
|
||||
}
|
||||
|
||||
if (class->parent)
|
||||
{
|
||||
class->parent->childs = eina_inlist_remove(class->parent->childs,
|
||||
EINA_INLIST_GET(class));
|
||||
}
|
||||
else
|
||||
{
|
||||
while (class->top->available)
|
||||
{
|
||||
Eina_Range *range;
|
||||
|
||||
range = EINA_INLIST_CONTAINER_GET(class->top->available, Eina_Range);
|
||||
class->top->available = eina_inlist_remove(class->top->available,
|
||||
class->top->available);
|
||||
eina_mempool_free(_eina_range_mp, range);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef EINA_HAVE_DEBUG_THREADS
|
||||
assert(pthread_equal(class->self, pthread_self()));
|
||||
#endif
|
||||
eina_lock_free(&class->mutex);
|
||||
|
||||
eina_mempool_del(class->mempool);
|
||||
eina_mempool_free(_eina_class_mp, class);
|
||||
}
|
||||
|
||||
void
|
||||
eina_class_repack(Eina_Class *class)
|
||||
{
|
||||
Eina_Class *child;
|
||||
|
||||
EINA_MAGIC_CHECK_CLASS(class);
|
||||
|
||||
if (!eina_lock_take(&class->mutex))
|
||||
{
|
||||
#ifdef EINA_HAVE_DEBUG_THREADS
|
||||
assert(pthread_equal(class->self, pthread_self()));
|
||||
#endif
|
||||
}
|
||||
|
||||
eina_mempool_repack(class->mempool, _eina_class_range_repack, class);
|
||||
|
||||
eina_lock_release(&class->mutex);
|
||||
|
||||
EINA_INLIST_FOREACH(class->childs, child)
|
||||
eina_class_repack(child);
|
||||
}
|
||||
|
||||
Eina_Object *
|
||||
eina_object_add(Eina_Class *class)
|
||||
{
|
||||
Eina_Class_Range *range;
|
||||
Eina_Object_Item **object;
|
||||
int localid;
|
||||
|
||||
EINA_MAGIC_CHECK_CLASS(class, NULL);
|
||||
|
||||
/* No need to lock the class as we don't access/modify the pointer inside
|
||||
* this function. */
|
||||
|
||||
range = _eina_class_empty_range_get(class->allocated_range);
|
||||
if (!range) range = _eina_class_range_add(class);
|
||||
|
||||
if (range->empty_count == 0)
|
||||
{
|
||||
ERR("The impossible happen, range is empty when it should not !");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
range->empty_count--;
|
||||
|
||||
object = eina_trash_pop(&range->empty);
|
||||
if (!object) object = range->pointer_array + range->current++;
|
||||
|
||||
localid = object - range->pointer_array;
|
||||
|
||||
*object = eina_mempool_malloc(class->mempool,
|
||||
class->object_size + _eina_object_item_size);
|
||||
|
||||
(*object)->index = localid;
|
||||
(*object)->link = NULL;
|
||||
(*object)->range = range;
|
||||
|
||||
_eina_object_constructor_call(class,
|
||||
((unsigned char*)(*object)) + _eina_object_item_size);
|
||||
|
||||
if (!(++range->generation_array[localid]))
|
||||
++range->generation_array[localid];
|
||||
|
||||
return _eina_object_get(*object);
|
||||
}
|
||||
|
||||
void *
|
||||
eina_object_pointer_get(Eina_Class *class,
|
||||
Eina_Object *object)
|
||||
{
|
||||
Eina_Object_Item *item;
|
||||
unsigned char *mem = NULL;
|
||||
|
||||
if (!object) return NULL;
|
||||
EINA_MAGIC_CHECK_CLASS(class, NULL);
|
||||
|
||||
if (!eina_lock_take(&class->mutex))
|
||||
{
|
||||
#ifdef EINA_HAVE_DEBUG_THREADS
|
||||
assert(pthread_equal(class->self, pthread_self()));
|
||||
#endif
|
||||
}
|
||||
|
||||
item = _eina_object_find_item(class, object);
|
||||
if (!item) goto on_error;
|
||||
|
||||
mem = (unsigned char*) item + _eina_object_item_size;
|
||||
|
||||
on_error:
|
||||
eina_lock_release(&class->mutex);
|
||||
|
||||
return mem;
|
||||
}
|
||||
|
||||
void
|
||||
eina_object_del(Eina_Class *class,
|
||||
Eina_Object *object)
|
||||
{
|
||||
Eina_Object_Item *item;
|
||||
|
||||
if (!object) return;
|
||||
EINA_MAGIC_CHECK_CLASS(class);
|
||||
|
||||
if (!eina_lock_take(&class->mutex))
|
||||
{
|
||||
#ifdef EINA_HAVE_DEBUG_THREADS
|
||||
assert(pthread_equal(class->self, pthread_self()));
|
||||
#endif
|
||||
}
|
||||
|
||||
item = _eina_object_find_item(class, object);
|
||||
if (!item) goto on_error;
|
||||
|
||||
_eina_object_item_del(item);
|
||||
|
||||
on_error:
|
||||
eina_lock_release(&class->mutex);
|
||||
}
|
||||
|
||||
Eina_Bool
|
||||
eina_object_parent_set(Eina_Class *parent_class, Eina_Object *parent,
|
||||
Eina_Class *object_class, Eina_Object *object)
|
||||
{
|
||||
Eina_Object_Item *parent_item;
|
||||
Eina_Object_Item *object_item;
|
||||
|
||||
if (!parent) return EINA_FALSE;
|
||||
if (!object) return EINA_FALSE;
|
||||
EINA_MAGIC_CHECK_CLASS(parent_class, EINA_FALSE);
|
||||
EINA_MAGIC_CHECK_CLASS(object_class, EINA_FALSE);
|
||||
|
||||
if (!eina_lock_take(&parent_class->mutex))
|
||||
{
|
||||
#ifdef EINA_HAVE_DEBUG_THREADS
|
||||
assert(pthread_equal(parent_class->self, pthread_self()));
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!eina_lock_take(&object_class->mutex))
|
||||
{
|
||||
#ifdef EINA_HAVE_DEBUG_THREADS
|
||||
assert(pthread_equal(object_class->self, pthread_self()));
|
||||
#endif
|
||||
}
|
||||
|
||||
parent_item = _eina_object_find_item(parent_class, parent);
|
||||
if (!parent_item) return EINA_FALSE;
|
||||
|
||||
object_item = _eina_object_find_item(object_class, object);
|
||||
if (!object_item) return EINA_FALSE;
|
||||
|
||||
if (object_item->parent)
|
||||
object_item->parent->link = eina_inlist_remove(object_item->parent->link,
|
||||
EINA_INLIST_GET(object_item));
|
||||
|
||||
object_item->parent = parent_item;
|
||||
parent_item->link = eina_inlist_append(parent_item->link,
|
||||
EINA_INLIST_GET(object_item));
|
||||
|
||||
eina_lock_release(&parent_class->mutex);
|
||||
eina_lock_release(&object_class->mutex);
|
||||
|
||||
return EINA_TRUE;
|
||||
}
|
||||
|
||||
Eina_Object *
|
||||
eina_object_parent_get(Eina_Class *class, Eina_Object *object)
|
||||
{
|
||||
Eina_Object_Item *object_item;
|
||||
Eina_Object *or = NULL;
|
||||
|
||||
if (!object) return EINA_FALSE;
|
||||
EINA_MAGIC_CHECK_CLASS(class, EINA_FALSE);
|
||||
|
||||
if (!eina_lock_take(&class->mutex))
|
||||
{
|
||||
#ifdef EINA_HAVE_DEBUG_THREADS
|
||||
assert(pthread_equal(class->self, pthread_self()));
|
||||
#endif
|
||||
}
|
||||
|
||||
object_item = _eina_object_find_item(class, object);
|
||||
if (object_item)
|
||||
or = _eina_object_get(object_item->parent);
|
||||
|
||||
eina_lock_release(&class->mutex);
|
||||
|
||||
return or;
|
||||
}
|
||||
|
|
@ -1,80 +0,0 @@
|
|||
/* EINA - EFL data type library
|
||||
* Copyright (C) 2011 Cedric Bail
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library;
|
||||
* if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef EINA_OBJECT_H__
|
||||
#define EINA_OBJECT_H__
|
||||
|
||||
#include "eina_config.h"
|
||||
|
||||
#include "eina_types.h"
|
||||
|
||||
/**
|
||||
* @addtogroup Eina_Object Object
|
||||
* @ingroup Eina
|
||||
*
|
||||
* @brief These functions manage object providing pointer checking
|
||||
* and memory repacking.
|
||||
*
|
||||
* Each Eina_Object is in fact only an ID and a generation count. This
|
||||
* make it possible to check if the ID is allocated by checking that it
|
||||
* is inside the boundary limit of the allocated range. The generation
|
||||
* count, give the possibility to check that we use a valid alive pointer
|
||||
* as generation is increased each time an object is allocated/destroyed.
|
||||
* And finally it provide type checking against Eina_Class.
|
||||
*
|
||||
* It is also to define link between object, then when father get deleted
|
||||
* all child will get deleted and their respective destructor will be called.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
typedef struct _Eina_Class Eina_Class;
|
||||
typedef struct _Eina_Object Eina_Object;
|
||||
|
||||
typedef void (*Eina_Class_Callback)(Eina_Class *c,
|
||||
void *object,
|
||||
void *data);
|
||||
|
||||
Eina_Class *eina_class_new(const char *name,
|
||||
unsigned int class_size,
|
||||
unsigned int pool_size,
|
||||
Eina_Class_Callback constructor,
|
||||
Eina_Class_Callback destructor,
|
||||
Eina_Class *parent,
|
||||
void *data);
|
||||
const char *eina_class_name_get(Eina_Class *c);
|
||||
unsigned int eina_class_size_get(Eina_Class *c);
|
||||
unsigned int eina_class_object_size_get(Eina_Class *c);
|
||||
void eina_class_del(Eina_Class *c);
|
||||
void eina_class_repack(Eina_Class *c);
|
||||
|
||||
Eina_Object *eina_object_add(Eina_Class *c);
|
||||
void *eina_object_pointer_get(Eina_Class *c,
|
||||
Eina_Object *object);
|
||||
void eina_object_del(Eina_Class *c,
|
||||
Eina_Object *object);
|
||||
|
||||
Eina_Bool eina_object_parent_set(Eina_Class *parent_class, Eina_Object *parent,
|
||||
Eina_Class *object_class, Eina_Object *object);
|
||||
Eina_Object *eina_object_parent_get(Eina_Class *c, Eina_Object *object);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue