From 16cfd9596abe600129fdb2b07ac4b6b264f7a6f7 Mon Sep 17 00:00:00 2001 From: tasn Date: Sun, 3 Jun 2012 08:42:12 +0000 Subject: [PATCH] Eo: Added support for static class ids. git-svn-id: http://svn.enlightenment.org/svn/e/trunk/PROTO/eobj@71656 7cbeb6ba-43b4-40fd-8cce-4c39aea84d33 --- lib/Eo.h | 56 ++++++++++++++++++++++++++++++++++++++++---- lib/eo.c | 54 ++++++++++++++++++++++++++++++++---------- lib/eo_base_class.c | 6 ++--- tests/eo_test_class_errors.c | 50 +++++++++++++++++++-------------------- tests/eo_test_general.c | 52 +++++++++++++++++++++++++++++++++------- 5 files changed, 164 insertions(+), 54 deletions(-) diff --git a/lib/Eo.h b/lib/Eo.h index 837bb62..9570fe9 100644 --- a/lib/Eo.h +++ b/lib/Eo.h @@ -35,6 +35,20 @@ extern "C" { #endif /** + * @def EO_OP_CLASS_OFFSET + * The bit offset of the class inside the ops. + * @internal + */ +#define EO_OP_CLASS_OFFSET 16 + +/** + * @def EO_CLASS_ID_TO_BASE_ID(class_id) + * Translates a class id to an op base id. + * @internal + */ +#define EO_CLASS_ID_TO_BASE_ID(class_id) ((class_id) << EO_OP_CLASS_OFFSET) + +/** * @var _eo_class_creation_lock * This variable is used for locking purposes in the class_get function * defined in #EO_DEFINE_CLASS. @@ -105,6 +119,13 @@ typedef unsigned int Eo_Op; typedef struct _Eo_Class Eo_Class; /** + * @typedef Eo_Class_Id + * An Id of a class. + * @ingroup Eo_Class + */ +typedef size_t Eo_Class_Id; + +/** * @def EO_NOOP * A special #Eo_Op meaning "No operation". */ @@ -193,6 +214,24 @@ typedef struct _Eo_Event_Description Eo_Event_Description; * You must use this macro if you want thread safety in class creation. */ #define EO_DEFINE_CLASS(class_get_func_name, class_desc, parent_class, ...) \ + EO_DEFINE_CLASS_STATIC(class_get_func_name, 0, class_desc, parent_class, __VA_ARGS__) + +/** + * @def EO_DEFINE_CLASS_STATIC(class_get_func_name, id, class_desc, parent_class, ...) + * *** DO NOT USE UNLESS YOU REALLY KNOW WHAT YOU ARE DOING *** + * @param id a positive number to serve as the id of the class. 0 means dynamic. See eo_class_new() for details. + * @param class_get_func_name the name of the wanted class_get function name. + * @param class_desc the class description. + * @param parent_class The parent class for the function. Look at eo_class_new() for more information. + * @param ... List of etxensions. Look at eo_class_new() for more information. + * + * This macro should only be used if you know what you are doing and you want + * to create a class with a static id. + * Use #EO_DEFINE_CLASS instead. + * + * @see #EO_DEFINE_CLASS + */ +#define EO_DEFINE_CLASS_STATIC(class_get_func_name, id, class_desc, parent_class, ...) \ EAPI const Eo_Class * \ class_get_func_name(void) \ { \ @@ -214,7 +253,7 @@ class_get_func_name(void) \ return _my_class; \ } \ eina_lock_release(&_eo_class_creation_lock); \ - _my_class = eo_class_new(class_desc, parent_class, __VA_ARGS__); \ + _my_class = eo_class_new(class_desc, id, parent_class, __VA_ARGS__); \ eina_lock_release(&_my_lock); \ \ eina_lock_take(&_eo_class_creation_lock); \ @@ -406,6 +445,7 @@ typedef struct _Eo_Class_Description Eo_Class_Description; /** * @brief Create a new class. * @param desc the class description to create the class with. + * @param id a positive number to serve as the id of the class. 0 means dynamic allocation. The number of static Ids is limited and regular users should not use static ids. * @param parent the class to inherit from. * @param ... A NULL terminated list of extensions (interfaces, mixins and the classes of any composite objects). * @return The new class's handle on success, or NULL otherwise. @@ -415,7 +455,7 @@ typedef struct _Eo_Class_Description Eo_Class_Description; * * @see #EO_DEFINE_CLASS */ -EAPI const Eo_Class *eo_class_new(const Eo_Class_Description *desc, const Eo_Class *parent, ...); +EAPI const Eo_Class *eo_class_new(const Eo_Class_Description *desc, Eo_Class_Id id, const Eo_Class *parent, ...); /** * @brief Sets the OP functions for a class. @@ -798,10 +838,16 @@ EAPI const Eo_Class *eo_base_class_get(void) EINA_CONST; typedef void (*eo_base_data_free_func)(void *); /** - * @var EO_BASE_BASE_ID + * @def EO_BASE_CLASS_ID + * #EO_BASE_CLASS 's class id. + */ +#define EO_BASE_CLASS_ID 1 + +/** + * @def EO_BASE_BASE_ID * #EO_BASE_CLASS 's base id. */ -extern EAPI Eo_Op EO_BASE_BASE_ID; +#define EO_BASE_BASE_ID EO_CLASS_ID_TO_BASE_ID(EO_BASE_CLASS_ID) enum { EO_BASE_SUB_ID_DATA_SET, @@ -829,7 +875,7 @@ enum { * Helper macro to get the full Op ID out of the sub_id for EO_BASE. * @param sub_id the sub id inside EO_BASE. */ -#define EO_BASE_ID(sub_id) (EO_BASE_BASE_ID + sub_id) +#define EO_BASE_ID(sub_id) (EO_BASE_BASE_ID + (sub_id)) /** * @def eo_base_data_set(key, data, free_func) diff --git a/lib/eo.c b/lib/eo.c index 02f617e..68c06e0 100644 --- a/lib/eo.c +++ b/lib/eo.c @@ -5,7 +5,8 @@ #include "config.h" -typedef size_t Eo_Class_Id; +/* The last id that should be reserved for statically allocated classes. */ +#define EO_STATIC_IDS_LAST 10 /* Used inside the class_get functions of classes, see #EO_DEFINE_CLASS */ EAPI Eina_Lock _eo_class_creation_lock; @@ -55,8 +56,7 @@ struct _Eo { #define DICH_CHAIN1(x) (((x) >> 16) & DICH_CHAIN1_MASK) #define DICH_CHAIN_LAST(x) ((x) & DICH_CHAIN_LAST_MASK) -#define OP_CLASS_OFFSET 16 -#define OP_CLASS_OFFSET_GET(x) (((x) >> OP_CLASS_OFFSET) & 0xffff) +#define OP_CLASS_OFFSET_GET(x) (((x) >> EO_OP_CLASS_OFFSET) & 0xffff) #define OP_CLASS_GET(op) ({ \ Eo_Class_Id tmp = OP_CLASS_OFFSET_GET(op); \ ID_CLASS_GET(tmp); \ @@ -591,8 +591,7 @@ _eo_class_base_op_init(Eo_Class *klass) if (!desc || !desc->ops.base_op_id) return; - /* FIXME: Depends on values defined above! */ - *(desc->ops.base_op_id) = klass->class_id << OP_CLASS_OFFSET; + *(desc->ops.base_op_id) = EO_CLASS_ID_TO_BASE_ID(klass->class_id); } #ifndef NDEBUG @@ -793,7 +792,7 @@ eo_class_free(Eo_Class *klass) /* DEVCHECK */ static Eina_Bool -_eo_class_check_op_descs(const Eo_Class *klass) +_eo_class_check_op_descs(const Eo_Class *klass, Eo_Class_Id id) { const Eo_Class_Description *desc = klass->desc; const Eo_Op_Description *itr; @@ -801,7 +800,7 @@ _eo_class_check_op_descs(const Eo_Class *klass) if (desc->ops.count > 0) { - if (!desc->ops.base_op_id) + if (((id == 0) || (id > EO_STATIC_IDS_LAST)) && !desc->ops.base_op_id) { ERR("Class '%s' has a non-zero ops count, but base_id is NULL.", desc->name); @@ -843,7 +842,7 @@ _eo_class_check_op_descs(const Eo_Class *klass) } EAPI const Eo_Class * -eo_class_new(const Eo_Class_Description *desc, const Eo_Class *parent, ...) +eo_class_new(const Eo_Class_Description *desc, Eo_Class_Id id, const Eo_Class *parent, ...) { Eo_Class *klass; va_list p_list; @@ -854,6 +853,12 @@ eo_class_new(const Eo_Class_Description *desc, const Eo_Class *parent, ...) return NULL; } + if (id > EO_STATIC_IDS_LAST) + { + ERR("Tried creating a class with the static id %d while the maximum static id is %d. Aborting.", id, EO_STATIC_IDS_LAST); + return NULL; + } + va_start(p_list, parent); EINA_SAFETY_ON_NULL_RETURN_VAL(desc, NULL); @@ -936,7 +941,7 @@ eo_class_new(const Eo_Class_Description *desc, const Eo_Class *parent, ...) EO_ALIGN_SIZE(klass->parent->desc->data_size); } - if (!_eo_class_check_op_descs(klass)) + if (!_eo_class_check_op_descs(klass, id)) { goto cleanup; } @@ -988,11 +993,36 @@ eo_class_new(const Eo_Class_Description *desc, const Eo_Class *parent, ...) } eina_lock_take(&_eo_class_creation_lock); - klass->class_id = ++_eo_classes_last_id; + + if (id == 0) + { + klass->class_id = ++_eo_classes_last_id; + } + else + { +#ifndef NDEBUG + if (_eo_classes && _eo_classes[id - 1]) + { + ERR("A class with id %d was already defined (%s). Aborting.", id, + _eo_classes[id - 1]->desc->name); + eina_lock_release(&_eo_class_creation_lock); + goto cleanup; + } +#endif + klass->class_id = id; + } + + { /* FIXME: Handle errors. */ + size_t arrsize = _eo_classes_last_id * sizeof(*_eo_classes); Eo_Class **tmp; - tmp = realloc(_eo_classes, _eo_classes_last_id * sizeof(*_eo_classes)); + tmp = realloc(_eo_classes, arrsize); + + /* If it's the first allocation, memset. */ + if (!_eo_classes) + memset(tmp, 0, arrsize); + _eo_classes = tmp; _eo_classes[klass->class_id - 1] = klass; } @@ -1396,7 +1426,7 @@ eo_init(void) eina_init(); _eo_classes = NULL; - _eo_classes_last_id = 0; + _eo_classes_last_id = EO_STATIC_IDS_LAST; _eo_log_dom = eina_log_domain_register(log_dom, EINA_COLOR_LIGHTBLUE); if (_eo_log_dom < 0) { diff --git a/lib/eo_base_class.c b/lib/eo_base_class.c index 5de6b3a..e5dc5d2 100644 --- a/lib/eo_base_class.c +++ b/lib/eo_base_class.c @@ -5,8 +5,6 @@ #include "config.h" -EAPI Eo_Op EO_BASE_BASE_ID = EO_NOOP; - static int event_freeze_count = 0; typedef struct @@ -578,7 +576,7 @@ static const Eo_Event_Description *event_desc[] = { static const Eo_Class_Description class_desc = { "Eo Base", EO_CLASS_TYPE_REGULAR_NO_INSTANT, - EO_CLASS_DESCRIPTION_OPS(&EO_BASE_BASE_ID, op_desc, EO_BASE_SUB_ID_LAST), + EO_CLASS_DESCRIPTION_OPS(NULL, op_desc, EO_BASE_SUB_ID_LAST), event_desc, sizeof(Private_Data), _constructor, @@ -587,5 +585,5 @@ static const Eo_Class_Description class_desc = { NULL }; -EO_DEFINE_CLASS(eo_base_class_get, &class_desc, NULL, NULL) +EO_DEFINE_CLASS_STATIC(eo_base_class_get, EO_BASE_CLASS_ID, &class_desc, NULL, NULL) diff --git a/tests/eo_test_class_errors.c b/tests/eo_test_class_errors.c index 0a10035..340d26c 100644 --- a/tests/eo_test_class_errors.c +++ b/tests/eo_test_class_errors.c @@ -45,46 +45,46 @@ START_TEST(eo_incomplete_desc) NULL }; - klass = eo_class_new(&class_desc, NULL, NULL); + klass = eo_class_new(&class_desc, 0, NULL, NULL); fail_if(klass); class_desc.ops.base_op_id = &TMP_BASE_ID; class_desc.ops.descs = NULL; - klass = eo_class_new(&class_desc, NULL, NULL); + klass = eo_class_new(&class_desc, 0, NULL, NULL); fail_if(klass); class_desc.ops.descs = op_desc; class_desc.ops.count = TEST_SUB_ID_LAST + 1; - klass = eo_class_new(&class_desc, NULL, NULL); + klass = eo_class_new(&class_desc, 0, NULL, NULL); fail_if(klass); class_desc.ops.count = 0; - klass = eo_class_new(&class_desc, NULL, NULL); + klass = eo_class_new(&class_desc, 0, NULL, NULL); fail_if(klass); class_desc.ops.count = TEST_SUB_ID_LAST; class_desc.ops.descs = op_desc_wrong; - klass = eo_class_new(&class_desc, NULL, NULL); + klass = eo_class_new(&class_desc, 0, NULL, NULL); fail_if(klass); class_desc.ops.descs = op_desc; class_desc.name = NULL; - klass = eo_class_new(&class_desc, NULL, NULL); + klass = eo_class_new(&class_desc, 0, NULL, NULL); fail_if(klass); class_desc.name = "Simple"; - klass = eo_class_new(NULL, NULL, NULL); + klass = eo_class_new(NULL, 0, NULL, NULL); fail_if(klass); /* Should create a class. */ - klass = eo_class_new(&class_desc, NULL, NULL); + klass = eo_class_new(&class_desc, 0, NULL, NULL); fail_if(!klass); (void) klass; @@ -137,18 +137,18 @@ START_TEST(eo_inherit_errors) NULL }; - klass_mixin = eo_class_new(&class_desc_mixin, NULL, NULL); + klass_mixin = eo_class_new(&class_desc_mixin, 0, NULL, NULL); fail_if(!klass_mixin); - klass_simple = eo_class_new(&class_desc_simple, NULL, NULL); + klass_simple = eo_class_new(&class_desc_simple, 0, NULL, NULL); fail_if(!klass_simple); - klass = eo_class_new(&class_desc, klass_simple, NULL); + klass = eo_class_new(&class_desc, 0, klass_simple, NULL); fail_if(klass); class_desc.type = EO_CLASS_TYPE_REGULAR; - klass = eo_class_new(&class_desc, klass_mixin, NULL); + klass = eo_class_new(&class_desc, 0, klass_mixin, NULL); fail_if(klass); (void) klass; @@ -214,22 +214,22 @@ START_TEST(eo_inconsistent_mro) NULL }; - klass_mixin = eo_class_new(&class_desc_mixin, NULL, NULL); + klass_mixin = eo_class_new(&class_desc_mixin, 0, NULL, NULL); fail_if(!klass_mixin); - klass_mixin2 = eo_class_new(&class_desc_mixin2, klass_mixin, NULL); + klass_mixin2 = eo_class_new(&class_desc_mixin2, 0, klass_mixin, NULL); fail_if(!klass_mixin2); - klass_mixin3 = eo_class_new(&class_desc_mixin3, klass_mixin, NULL); + klass_mixin3 = eo_class_new(&class_desc_mixin3, 0, klass_mixin, NULL); fail_if(!klass_mixin3); - klass = eo_class_new(&class_desc_simple, EO_BASE_CLASS, klass_mixin, klass_mixin2, NULL); + klass = eo_class_new(&class_desc_simple, 0, EO_BASE_CLASS, klass_mixin, klass_mixin2, NULL); fail_if(klass); - klass = eo_class_new(&class_desc_simple, EO_BASE_CLASS, klass_mixin2, klass_mixin, NULL); + klass = eo_class_new(&class_desc_simple, 0, EO_BASE_CLASS, klass_mixin2, klass_mixin, NULL); fail_if(!klass); - klass = eo_class_new(&class_desc_simple, EO_BASE_CLASS, klass_mixin2, klass_mixin3, NULL); + klass = eo_class_new(&class_desc_simple, 0, EO_BASE_CLASS, klass_mixin2, klass_mixin3, NULL); fail_if(!klass); eo_shutdown(); @@ -257,36 +257,36 @@ START_TEST(eo_bad_interface) NULL }; - klass = eo_class_new(&class_desc, NULL, NULL); + klass = eo_class_new(&class_desc, 0, NULL, NULL); fail_if(klass); class_desc.data_size = 0; class_desc.constructor = _stub_constructor; - klass = eo_class_new(&class_desc, NULL, NULL); + klass = eo_class_new(&class_desc, 0, NULL, NULL); fail_if(klass); class_desc.constructor = NULL; class_desc.destructor = _stub_constructor; - klass = eo_class_new(&class_desc, NULL, NULL); + klass = eo_class_new(&class_desc, 0, NULL, NULL); fail_if(klass); class_desc.destructor = NULL; class_desc.class_constructor = _stub_class_constructor; - klass = eo_class_new(&class_desc, NULL, NULL); + klass = eo_class_new(&class_desc, 0, NULL, NULL); fail_if(klass); class_desc.class_constructor = NULL; class_desc.class_destructor = _stub_class_constructor; - klass = eo_class_new(&class_desc, NULL, NULL); + klass = eo_class_new(&class_desc, 0, NULL, NULL); fail_if(klass); class_desc.class_destructor = NULL; - klass = eo_class_new(&class_desc, NULL, NULL); + klass = eo_class_new(&class_desc, 0, NULL, NULL); fail_if(!klass); eo_shutdown(); @@ -349,7 +349,7 @@ START_TEST(eo_op_types) NULL }; - klass = eo_class_new(&class_desc, SIMPLE_CLASS, NULL); + klass = eo_class_new(&class_desc, 0, SIMPLE_CLASS, NULL); fail_if(!klass); Eo *obj = eo_add(klass, NULL); diff --git a/tests/eo_test_general.c b/tests/eo_test_general.c index 15404e8..7b26062 100644 --- a/tests/eo_test_general.c +++ b/tests/eo_test_general.c @@ -36,7 +36,7 @@ START_TEST(eo_data_fetch) NULL }; - const Eo_Class *klass = eo_class_new(&class_desc, EO_BASE_CLASS, NULL); + const Eo_Class *klass = eo_class_new(&class_desc, 0, EO_BASE_CLASS, NULL); fail_if(!klass); Eo *obj = eo_add(klass, NULL); @@ -47,7 +47,7 @@ START_TEST(eo_data_fetch) eo_unref(obj); class_desc.data_size = 0; - klass = eo_class_new(&class_desc, EO_BASE_CLASS, NULL); + klass = eo_class_new(&class_desc, 0, EO_BASE_CLASS, NULL); fail_if(!klass); obj = eo_add(klass, NULL); @@ -59,6 +59,41 @@ START_TEST(eo_data_fetch) } END_TEST +START_TEST(eo_static_classes) +{ + eo_init(); + + static const Eo_Op_Description op_desc[] = { + EO_OP_DESCRIPTION(SIMPLE_SUB_ID_A_SET, "i", "Set property A"), + EO_OP_DESCRIPTION_SENTINEL + }; + + /* Usually should be const, not const only for the test... */ + static Eo_Class_Description class_desc = { + "Simple2", + EO_CLASS_TYPE_REGULAR, + EO_CLASS_DESCRIPTION_OPS(NULL, op_desc, 1), + NULL, + 0, + NULL, + NULL, + NULL, + NULL + }; + + const Eo_Class *klass = eo_class_new(&class_desc, 1, EO_BASE_CLASS, NULL); + fail_if(klass); + + klass = eo_class_new(&class_desc, 1000, EO_BASE_CLASS, NULL); + fail_if(klass); + + klass = eo_class_new(&class_desc, 2, EO_BASE_CLASS, NULL); + fail_if(!klass); + + eo_shutdown(); +} +END_TEST + static void _man_con(Eo *obj, void *data EINA_UNUSED) { @@ -90,7 +125,7 @@ START_TEST(eo_man_free) NULL }; - const Eo_Class *klass = eo_class_new(&class_desc, EO_BASE_CLASS, NULL); + const Eo_Class *klass = eo_class_new(&class_desc, 0, EO_BASE_CLASS, NULL); fail_if(!klass); Eo *obj = eo_add(klass, NULL); @@ -103,7 +138,7 @@ START_TEST(eo_man_free) eo_unref(obj); class_desc.destructor = NULL; - klass = eo_class_new(&class_desc, EO_BASE_CLASS, NULL); + klass = eo_class_new(&class_desc, 0, EO_BASE_CLASS, NULL); fail_if(!klass); obj = eo_add(klass, NULL); @@ -118,7 +153,7 @@ START_TEST(eo_man_free) eo_manual_free(obj); class_desc.constructor = NULL; - klass = eo_class_new(&class_desc, EO_BASE_CLASS, NULL); + klass = eo_class_new(&class_desc, 0, EO_BASE_CLASS, NULL); fail_if(!klass); obj = eo_add(klass, NULL); @@ -275,13 +310,13 @@ START_TEST(eo_op_errors) NULL }; - const Eo_Class *klass = eo_class_new(&class_desc, SIMPLE_CLASS, NULL); + const Eo_Class *klass = eo_class_new(&class_desc, 0, SIMPLE_CLASS, NULL); fail_if(!klass); Eo *obj = eo_add(klass, NULL); /* Out of bounds op for a legal class. */ - fail_if(eo_do(obj, 0x00010111)); + fail_if(eo_do(obj, EO_BASE_ID(0x0111))); /* Ilegal class. */ fail_if(eo_do(obj, 0x0F010111)); @@ -413,7 +448,7 @@ START_TEST(eo_magic_checks) eo_class_do((Eo_Class *) buf, NULL); eo_class_do_super((Eo_Class *) buf, EO_NOOP); - fail_if(eo_class_new(NULL, (Eo_Class *) buf), NULL); + fail_if(eo_class_new(NULL, 0, (Eo_Class *) buf), NULL); eo_xref(obj, (Eo *) buf); eo_xunref(obj, (Eo *) buf); @@ -472,4 +507,5 @@ void eo_test_general(TCase *tc) tcase_add_test(tc, eo_magic_checks); tcase_add_test(tc, eo_data_fetch); tcase_add_test(tc, eo_man_free); + tcase_add_test(tc, eo_static_classes); } -- 2.7.4