eolian_cxx: Fix "dreaded diamond" inheritance problem for C++ wrappers

Solved diamond inheritance problem by completely removing inheritance in
the abstract class.
All ancestors are inherited directly in the concrete class.
The algorithm that list the ancestors also avoid repetition.

Now concrete classes define methods too. This helps referring the correct
method directly by the object type (when there are methods with the same
name).

Moved the declaration and definition of constructor methods to the concrete
class, since they should not be used in derived classes.

Updated example that call "color_set".
With this model, if two ancestor classes have a method with the same name,
to call one of them from a derived class you must write the scoped name of
the member function in the wrapper.
In this case, either Evas.Object and Evas.SmartObject have a property
named "color".

Added "from_global" option to the full_name grammar too.
This commit is contained in:
Vitor Sousa 2014-12-19 14:34:15 -02:00
parent ed75aa32d6
commit 6519ae6ed9
6 changed files with 48 additions and 42 deletions

View File

@ -1,5 +1,6 @@
#include <vector>
#include <set>
#include <algorithm>
#include <cassert>
#include <cstddef>
@ -23,8 +24,11 @@ namespace eolian_cxx {
extern efl::eina::log_domain domain;
void
remove_repeated_base(const char* klass_name, efl::eolian::parents_container_type& cont)
add_parent_recursive(const char* klass_name, std::set<std::string>& parents)
{
if (!klass_name)
return;
Eolian_Class const* klass = ::eolian_class_get_by_name(klass_name);
if (!klass)
{
@ -32,20 +36,14 @@ remove_repeated_base(const char* klass_name, efl::eolian::parents_container_type
return;
}
parents.insert(class_format_cxx(safe_lower(klass_name)));
Eina_Iterator* inheritances = ::eolian_class_inherits_get(klass);
void* curr = 0;
EINA_ITERATOR_FOREACH(inheritances, curr)
{
if (!curr)
continue;
const char* parent = static_cast<const char*>(curr);
cont.erase(
std::remove(cont.begin(), cont.end(), safe_lower(class_format_cxx(parent)))
, cont.end());
remove_repeated_base(parent, cont);
add_parent_recursive(static_cast<const char*>(curr), parents);
}
eina_iterator_free(inheritances);
}
@ -184,23 +182,15 @@ convert_eolian_inheritances(efl::eolian::eo_class& cls, Eolian_Class const& klas
::eolian_class_inherits_get(&klass);
void *curr;
std::set<std::string> parents;
EINA_ITERATOR_FOREACH(inheritances, curr)
{
std::string parent = safe_lower(static_cast<const char*>(curr));
cls.parents.push_back(class_format_cxx(parent));
add_parent_recursive(static_cast<const char*>(curr), parents);
}
eina_iterator_free(inheritances);
if (cls.parents.empty())
return;
inheritances = ::eolian_class_inherits_get(&klass);
EINA_ITERATOR_FOREACH(inheritances, curr)
{
if (curr)
remove_repeated_base(static_cast<const char*>(curr), cls.parents);
}
eina_iterator_free(inheritances);
cls.parents.assign(parents.begin(), parents.end());
}
void

View File

@ -74,7 +74,7 @@ example_complex_types()
efl::evas::grid grid(efl::eo::parent = canvas);
grid.position_set(0, 0);
grid.color_set(0, 0, 0, 255);
grid.object_smart::color_set(0, 0, 0, 255);
grid.size_set(5, 5);
grid.visibility_set(true);

View File

@ -46,8 +46,7 @@ operator<<(std::ostream& out, class_inheritance const& x)
last = cls.parents.cend();
for (it = first; it != last; ++it)
{
out << tab(2) << (it == first ? ": " : ", ")
<< "::" << abstract_namespace << "::" << *it << endl;
out << tab(2) << ", ::" << abstract_namespace << "::" << *it << endl;
}
return out;
}
@ -241,9 +240,9 @@ operator<<(std::ostream& out, constructor_method_function_definitions const& x)
}
out << template_parameters_declaration(c.params, 0)
<< "inline " << abstract_full_name(x._cls)
<< "inline " << full_name(x._cls)
<< "::" << constructor_functor_type_decl(c) << " "
<< abstract_full_name(x._cls, false) << "::" << c.name << "("
<< full_name(x._cls, false) << "::" << c.name << "("
<< parameters_declaration(c.params) << ") const" << endl
<< "{" << endl
<< tab(1) << "return " << constructor_functor_type_decl(c) << "("

View File

@ -61,8 +61,9 @@ struct function_definition
{
eo_class const& _cls;
eo_function const& _func;
function_definition(eo_class const& cls, eo_function const& func)
: _cls(cls), _func(func)
bool _concrete;
function_definition(eo_class const& cls, eo_function const& func, bool concrete)
: _cls(cls), _func(func), _concrete(concrete)
{}
};
@ -74,8 +75,14 @@ operator<<(std::ostream& out, function_definition const& x)
bool is_static = function_is_static(func);
out << template_parameters_declaration(func.params, 0)
<< "inline " << reinterpret_type(func.ret) << " "
<< abstract_full_name(x._cls, false) << "::" << func.name << "("
<< "inline " << reinterpret_type(func.ret) << " ";
if (x._concrete)
out << full_name(x._cls, false);
else
out << abstract_full_name(x._cls, false);
out << "::" << func.name << "("
<< parameters_declaration(func.params)
<< (is_static ? ")" : ") const") << endl
<< "{" << endl;
@ -121,8 +128,10 @@ operator<<(std::ostream& out, function_declarations const& x)
struct function_definitions
{
eo_class const& _cls;
function_definitions(eo_class const& cls)
bool _concrete;
function_definitions(eo_class const& cls, bool concrete)
: _cls(cls)
, _concrete(concrete)
{}
};
@ -131,7 +140,7 @@ operator<<(std::ostream& out, function_definitions const& x)
{
for (eo_function const& f : x._cls.functions)
{
out << function_definition(x._cls, f) << endl;
out << function_definition(x._cls, f, x._concrete) << endl;
}
return out;
}

View File

@ -105,10 +105,7 @@ eo_class_generator(std::ostream& out, eo_class const& cls)
<< namespace_head(cls)
<< comment(cls.comment)
<< "struct " << cls.name << endl
<< class_inheritance(cls)
<< '{' << endl
<< functors_constructor_methods(cls)
<< constructor_method_function_declarations(cls)
<< function_declarations(cls)
<< events(cls)
<< eo_class_getter(cls)
@ -120,22 +117,29 @@ eo_class_generator(std::ostream& out, eo_class const& cls)
<< "}" << endl << endl
<< namespace_head(cls)
<< "struct " << cls.name << endl
<< tab(2) << ": " << abstract_full_name(cls) << endl
<< tab(2) << ", ::efl::eo::concrete" << endl
<< tab(2) << ": ::efl::eo::concrete" << endl
<< class_inheritance(cls)
<< '{' << endl
<< functors_constructor_methods(cls)
<< constructor_with_constructor_methods(cls)
<< constructor_eo(cls)
<< copy_constructor(cls)
<< destructor(cls)
<< constructor_method_function_declarations(cls)
<< function_declarations(cls)
<< events(cls)
<< eo_class_getter(cls)
<< "private:" << endl
<< function_call_constructor_methods(cls)
<< tab(2) << "Eo* _concrete_eo_ptr() const { return _eo_ptr(); }" << endl
<< "};" << endl << endl
<< "static_assert(sizeof(" << full_name(cls) << ") == sizeof(Eo*), \"\");" << endl
<< "static_assert(std::is_standard_layout<" << full_name(cls) << ">::value, \"\");" << endl
<< endl
<< namespace_tail(cls)
<< constructor_method_function_definitions(cls)
<< function_definitions(cls)
<< function_definitions(cls, true)
<< function_definitions(cls, false)
<< class_implicit_conversion_definition(cls);
}

View File

@ -15,15 +15,19 @@ using std::endl;
struct full_name
{
eo_class const& _cls;
full_name(eo_class const& cls) : _cls(cls) {}
bool _from_global;
full_name(eo_class const& cls, bool from_global = true)
: _cls(cls), _from_global(from_global) {}
};
inline std::ostream&
operator<<(std::ostream& out, full_name const& x)
{
if (x._from_global)
out << "::";
if(!x._cls.name_space.empty())
out << "::" << x._cls.name_space;
return out << "::" << x._cls.name;
out << x._cls.name_space << "::";
return out << x._cls.name;
}
struct abstract_full_name