RNA C++: collections functions are now properly handled, meaning it is now
authorBrecht Van Lommel <brechtvanlommel@pandora.be>
Sat, 3 Nov 2012 15:35:43 +0000 (15:35 +0000)
committerBrecht Van Lommel <brechtvanlommel@pandora.be>
Sat, 3 Nov 2012 15:35:43 +0000 (15:35 +0000)
possible to call BlendData.meshes.remove() directly.

It requires special order of classes in header file (namely classes used for
collection functions should be declared before collection properties with this
classes are declared). Currently used naive linear search for this, could be
replaced with hash or bisect, but for now performance here is not an issue.

Patch by Sergey, but committing now because it's needed for next commit.

source/blender/makesrna/intern/makesrna.c

index a10f2b44d25ad5e4fac940aff36a729559798e98..7c4ce3d18d7fc67a3bdb19810f412d2e8277fb40 100644 (file)
@@ -1677,13 +1677,17 @@ static void rna_def_property_funcs_header_cpp(FILE *f, StructRNA *srna, Property
                case PROP_COLLECTION:
                {
                        CollectionPropertyRNA *cprop = (CollectionPropertyRNA *)dp->prop;
+                       const char *collection_funcs = "DefaultCollectionFunctions";
+
+                       if (!(dp->prop->flag & (PROP_IDPROPERTY | PROP_BUILTIN)) && cprop->property.srna)
+                               collection_funcs  = (char*)cprop->property.srna;
 
                        if (cprop->item_type)
-                               fprintf(f, "\tCOLLECTION_PROPERTY(%s, %s, %s, %s, %s, %s)", (const char *)cprop->item_type, srna->identifier,
+                               fprintf(f, "\tCOLLECTION_PROPERTY(%s, %s, %s, %s, %s, %s, %s)", collection_funcs, (const char *)cprop->item_type, srna->identifier,
                                        rna_safe_id(prop->identifier), (cprop->length ? "TRUE" : "FALSE"),
                                        (cprop->lookupint ? "TRUE" : "FALSE"), (cprop->lookupstring ? "TRUE" : "FALSE"));
                        else
-                               fprintf(f, "\tCOLLECTION_PROPERTY(%s, %s, %s, %s, %s, %s)", "UnknownType", srna->identifier,
+                               fprintf(f, "\tCOLLECTION_PROPERTY(%s, %s, %s, %s, %s, %s, %s)", collection_funcs, "UnknownType", srna->identifier,
                                        rna_safe_id(prop->identifier), (cprop->length ? "TRUE" : "FALSE"),
                                        (cprop->lookupint ? "TRUE" : "FALSE"), (cprop->lookupstring ? "TRUE" : "FALSE"));
                        break;
@@ -3414,7 +3418,7 @@ static const char *cpp_classes = ""
 "      inline static int sname##_##identifier##_lookup_string_wrap(PointerRNA *ptr, const char *key, PointerRNA *r_ptr) \\\n"
 "      { return sname##_##identifier##_lookup_string(ptr, key, r_ptr); } \n"
 "\n"
-"#define COLLECTION_PROPERTY(type, sname, identifier, has_length, has_lookup_int, has_lookup_string) \\\n"
+"#define COLLECTION_PROPERTY(collection_funcs, type, sname, identifier, has_length, has_lookup_int, has_lookup_string) \\\n"
 "      typedef CollectionIterator<type, sname##_##identifier##_begin, \\\n"
 "              sname##_##identifier##_next, sname##_##identifier##_end> identifier##_iterator; \\\n"
 "      COLLECTION_PROPERTY_LENGTH_##has_length(sname, identifier) \\\n"
@@ -3423,7 +3427,7 @@ static const char *cpp_classes = ""
 "      Collection<sname, type, sname##_##identifier##_begin, \\\n"
 "              sname##_##identifier##_next, sname##_##identifier##_end, \\\n"
 "              sname##_##identifier##_length_wrap, \\\n"
-"              sname##_##identifier##_lookup_int_wrap, sname##_##identifier##_lookup_string_wrap> identifier;\n"
+"              sname##_##identifier##_lookup_int_wrap, sname##_##identifier##_lookup_string_wrap, collection_funcs> identifier;\n"
 "\n"
 "class Pointer {\n"
 "public:\n"
@@ -3511,10 +3515,11 @@ static const char *cpp_classes = ""
 "};\n"
 "\n"
 "template<typename Tp, typename T, TBeginFunc Tbegin, TNextFunc Tnext, TEndFunc Tend,\n"
-"         TLengthFunc Tlength, TLookupIntFunc Tlookup_int, TLookupStringFunc Tlookup_string>\n"
-"class Collection {\n"
+"         TLengthFunc Tlength, TLookupIntFunc Tlookup_int, TLookupStringFunc Tlookup_string,\n"
+"         typename Tcollection_funcs>\n"
+"class Collection : public Tcollection_funcs {\n"
 "public:\n"
-"      Collection(const PointerRNA &p) : ptr(p) {}\n"
+"      Collection(const PointerRNA &p) : Tcollection_funcs(p), ptr(p)  {}\n"
 "\n"
 "      void begin(CollectionIterator<T, Tbegin, Tnext, Tend>& iter)\n"
 "      { iter.begin(ptr); }\n"
@@ -3531,14 +3536,75 @@ static const char *cpp_classes = ""
 "private:\n"
 "      PointerRNA ptr;\n"
 "};\n"
+"\n"
+"class DefaultCollectionFunctions {\n"
+"public:\n"
+"      DefaultCollectionFunctions(const PointerRNA &p) {}\n"
+"};\n"
+"\n"
 "\n";
 
+static int rna_is_collection_prop(PropertyRNA *prop)
+{
+       if (!(prop->flag & (PROP_IDPROPERTY | PROP_BUILTIN)))
+               if (prop->type == PROP_COLLECTION)
+                       return 1;
+
+       return 0;
+}
+
+static int rna_is_collection_functions_struct(const char **collection_structs, const char *struct_name)
+{
+       int a = 0, found = 0;
+
+       while (collection_structs[a]) {
+               if (!strcmp(collection_structs[a], struct_name)) {
+                       found = 1;
+                       break;
+               }
+               a++;
+       }
+
+       return found;
+}
+
+static void rna_generate_header_class_cpp(StructDefRNA *ds, FILE *f)
+{
+       StructRNA *srna = ds->srna;
+       PropertyDefRNA *dp;
+       FunctionDefRNA *dfunc;
+
+       fprintf(f, "/**************** %s ****************/\n\n", srna->name);
+
+       fprintf(f, "class %s : public %s {\n", srna->identifier, (srna->base) ? srna->base->identifier : "Pointer");
+       fprintf(f, "public:\n");
+       fprintf(f, "\t%s(const PointerRNA &ptr_arg) :\n\t\t%s(ptr_arg)", srna->identifier,
+                       (srna->base) ? srna->base->identifier : "Pointer");
+       for (dp = ds->cont.properties.first; dp; dp = dp->next)
+               if (rna_is_collection_prop(dp->prop))
+                               fprintf(f, ",\n\t\t%s(ptr_arg)", dp->prop->identifier);
+       fprintf(f, "\n\t\t{}\n\n");
+
+       for (dp = ds->cont.properties.first; dp; dp = dp->next)
+               rna_def_property_funcs_header_cpp(f, ds->srna, dp);
+
+       fprintf(f, "\n");
+       for (dfunc = ds->functions.first; dfunc; dfunc = dfunc->cont.next)
+               rna_def_struct_function_header_cpp(f, srna, dfunc);
+
+       fprintf(f, "};\n\n");
+}
+
 static void rna_generate_header_cpp(BlenderRNA *UNUSED(brna), FILE *f)
 {
        StructDefRNA *ds;
        PropertyDefRNA *dp;
        StructRNA *srna;
        FunctionDefRNA *dfunc;
+       const char *first_collection_func_struct = NULL;
+       const char *collection_func_structs[256] = {NULL};
+       int all_collection_func_structs = 0;
+       int max_collection_func_structs = sizeof(collection_func_structs) / sizeof(collection_func_structs[0]) - 1;
 
        fprintf(f, "\n#ifndef __RNA_BLENDER_CPP_H__\n");
        fprintf(f, "#define __RNA_BLENDER_CPP_H__\n\n");
@@ -3555,33 +3621,59 @@ static void rna_generate_header_cpp(BlenderRNA *UNUSED(brna), FILE *f)
 
        fprintf(f, "/**************** Declarations ****************/\n\n");
 
-       for (ds = DefRNA.structs.first; ds; ds = ds->cont.next)
+       for (ds = DefRNA.structs.first; ds; ds = ds->cont.next) {
                fprintf(f, "class %s;\n", ds->srna->identifier);
+       }
        fprintf(f, "\n");
 
+       /* first get list of all structures used as collection functions, so they'll be declared first */
        for (ds = DefRNA.structs.first; ds; ds = ds->cont.next) {
-               srna = ds->srna;
+               for (dp = ds->cont.properties.first; dp; dp = dp->next) {
+                       if (rna_is_collection_prop(dp->prop)) {
+                               PropertyRNA *prop = dp->prop;
+
+                               if (prop->srna) {
+                                       /* store name of structure which first uses custom functions for collections */
+                                       if (first_collection_func_struct == NULL)
+                                               first_collection_func_struct = ds->srna->identifier;
+
+                                       if (!rna_is_collection_functions_struct(collection_func_structs, (char*)prop->srna)) {
+                                               if (all_collection_func_structs >= max_collection_func_structs) {
+                                                       printf("Array size to store all collection structures names is too small\n");
+                                                       exit(1);
+                                               }
 
-               fprintf(f, "/**************** %s ****************/\n\n", srna->name);
+                                               collection_func_structs[all_collection_func_structs++] = (char*)prop->srna;
+                                       }
+                               }
+                       }
+               }
+       }
 
-               fprintf(f, "class %s : public %s {\n", srna->identifier, (srna->base) ? srna->base->identifier : "Pointer");
-               fprintf(f, "public:\n");
-               fprintf(f, "\t%s(const PointerRNA &ptr_arg) :\n\t\t%s(ptr_arg)", srna->identifier,
-                       (srna->base) ? srna->base->identifier : "Pointer");
-               for (dp = ds->cont.properties.first; dp; dp = dp->next)
-                       if (!(dp->prop->flag & (PROP_IDPROPERTY | PROP_BUILTIN)))
-                               if (dp->prop->type == PROP_COLLECTION)
-                                       fprintf(f, ",\n\t\t%s(ptr_arg)", dp->prop->identifier);
-               fprintf(f, "\n\t\t{}\n\n");
+       /* declare all structures in such order:
+        * - first N structures which doesn't use custom functions for collections
+        * - all structures used for custom functions in collections
+        * - all the rest structures
+        * such an order prevents usage of non-declared classes
+        */
+       for (ds = DefRNA.structs.first; ds; ds = ds->cont.next) {
+               srna = ds->srna;
 
-               for (dp = ds->cont.properties.first; dp; dp = dp->next)
-                       rna_def_property_funcs_header_cpp(f, ds->srna, dp);
+               if (!strcmp(srna->identifier, first_collection_func_struct)) {
+                       StructDefRNA *ds2;
+                       StructRNA *srna2;
 
-               fprintf(f, "\n");
-               for (dfunc = ds->functions.first; dfunc; dfunc = dfunc->cont.next)
-                       rna_def_struct_function_header_cpp(f, srna, dfunc);
+                       for (ds2 = DefRNA.structs.first; ds2; ds2 = ds2->cont.next) {
+                               srna2 = ds2->srna;
+
+                               if (rna_is_collection_functions_struct(collection_func_structs, srna2->identifier)) {
+                                       rna_generate_header_class_cpp(ds2, f);
+                               }
+                       }
+               }
 
-               fprintf(f, "};\n\n");
+               if (!rna_is_collection_functions_struct(collection_func_structs, srna->identifier))
+                       rna_generate_header_class_cpp(ds, f);
        }
 
        fprintf(f, "} /* namespace BL */\n");