Eo: Added support for static class ids.
authortasn <tasn>
Sun, 3 Jun 2012 08:42:12 +0000 (08:42 +0000)
committertasn <tasn@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Sun, 3 Jun 2012 08:42:12 +0000 (08:42 +0000)
git-svn-id: http://svn.enlightenment.org/svn/e/trunk/PROTO/eobj@71656 7cbeb6ba-43b4-40fd-8cce-4c39aea84d33

lib/Eo.h
lib/eo.c
lib/eo_base_class.c
tests/eo_test_class_errors.c
tests/eo_test_general.c

index 837bb62..9570fe9 100644 (file)
--- 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)
index 02f617e..68c06e0 100644 (file)
--- 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)
      {
index 5de6b3a..e5dc5d2 100644 (file)
@@ -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)
 
index 0a10035..340d26c 100644 (file)
@@ -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);
index 15404e8..7b26062 100644 (file)
@@ -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);
 }